2012-05-01 25 views

Trả lời

12

Cuối cùng tôi đã tìm thấy câu trả lời cho điều này! Đó là một chút hacky, nhưng không quá nhiều. Nhược điểm duy nhất là:

  1. Nó sử dụng API 3.0+. Nghiêm túc mặc dù Google, điểm phát hành phiên bản Android mới là gì nếu chúng ta không thể sử dụng chúng?/rant.
  2. Bạn phải thay thế số MenuItem bằng số View của riêng bạn. An ImageView khá giống với tiêu chuẩn nhưng nó bỏ qua các tính năng như nhấn và giữ đầu công cụ, và có thể là những thứ khác.
  3. Tôi chưa thử nghiệm rất nhiều.

Ok, đây là cách chúng tôi thực hiện. Thay đổi Activity 's onCreateOptionsMenu() một cái gì đó như thế này của bạn:

View mAddListingButton; 

@Override 
public boolean onCreateOptionsMenu(Menu menu) 
{ 
    getMenuInflater().inflate(R.menu.activity_main, menu); 

    // Find the menu item we are interested in. 
    MenuItem it = menu.findItem(R.id.item_new_listing); 

    // Create a new view to replace the standard one. 
    // It would be nice if we could just *get* the standard one 
    // but unfortunately it.getActionView() returns null. 

    // actionButtonStyle makes the 'pressed' state work. 
    ImageView button = new ImageView(this, null, android.R.attr.actionButtonStyle); 
    button.setImageResource(R.drawable.ic_action_add_listing); 
    // The onClick attributes in the menu resource no longer work (I assume since 
    // we passed null as the attribute list when creating this button. 
    button.setOnClickListener(this); 

    // Ok, now listen for when layouting is finished and the button is in position. 
    button.addOnLayoutChangeListener(new OnLayoutChangeListener() { 
     @Override 
     public void onLayoutChange(View v, int left, int top, int right, int bottom, 
       int oldLeft, int oldTop, int oldRight, int oldBottom) 
     { 
      // Apparently this can be called before layout is finished, so ignore it. 
      // Remember also that it might never be called with sane values, for example 
      // if your action button is pushed into the "more" menu thing. 
      if (left == 0 && top == 0 && right == 0 && bottom == 0) 
       return; 

      // This is the only way to get the absolute position on the screen. 
      // The parameters passed to this function are relative to the containing View 
      // and v.getX/Y() return 0. 
      int[] location = new int[2]; 
      v.getLocationOnScreen(location); 

      // Ok, now we know the centre location of the button in screen coordinates! 
      informButtonLocation(location[0] + (right-left)/2, location[1] + (bottom-top)/2); 
     } 
    }); 

    it.setActionView(button); 
    mAddListingButton = it.getActionView(); 
    return true; 
} 

Và sau đó bạn có một chức năng cập nhật hướng dẫn hữu ích của bạn xem xung quanh vị trí của các nút và vẽ lại nó:

private void informButtonLocation(int cx, int cy) 
{ 
    MyHelpView v = (MyHelpView)findViewById(R.id.instructions); 
    v.setText("Click this button."); 
      v.setTarget(cx, cy); 
} 

Cuối cùng làm cho bạn ưa thích schmancy tùy chỉnh xem mà rút ra một mũi tên để (gần) nút. Trong phương thức onDraw của bạn, bạn có thể chuyển đổi tọa độ màn hình trở lại Canvas tọa độ sử dụng cùng chức năng getLocationOnScreen.Một cái gì đó như thế này:

@Override 
public void onDraw(Canvas canvas) 
{ 
    int[] location = new int[2]; 
    getLocationOnScreen(location); 

    canvas.drawColor(Color.WHITE); 

    mPaint.setColor(Color.BLACK); 
    mPaint.setTextSize(40); 
    mPaint.setAntiAlias(true); 
    mPaint.setTextAlign(Align.CENTER); 
    canvas.drawText(mText, getWidth()/2, getHeight()/2, mPaint); 

    // Crappy line that isn't positioned right at all and has no arrowhead. 
    if (mTargetX != -1 && mTargetY != -1) 
     canvas.drawLine(getWidth()/2, getHeight()/2, 
       mTargetX - location[0], mTargetY - location[1], mPaint); 
} 

(Nhưng rõ ràng bạn phải cắt vị trí mục tiêu vào kích thước Canvas). Nếu bạn đi cho cùng một phương pháp như Google, nơi bạn che phủ một cái nhìn trên toàn bộ màn hình, bạn sẽ không phải lo lắng về điều đó, nhưng nó là xâm nhập hơn. Phương pháp của Google chắc chắn không sử dụng bất kỳ API riêng tư nào (đáng ngạc nhiên). Kiểm tra Cling.java trong mã Launcher2.

Ngẫu nhiên, nếu bạn nhìn vào nguồn để thực hiện tương tự của Google này cho trình khởi chạy (họ gọi màn hình hướng dẫn là Cling vì một số lý do), bạn có thể thấy rằng nó còn khó hiểu hơn. Về cơ bản, họ sử dụng các vị trí màn hình tuyệt đối được xác định theo bố cục nào đang được sử dụng.

Hy vọng điều này sẽ giúp mọi người!

+0

Điều này thực sự hoạt động tốt! Mặc dù thời gian đã qua để nó có ích cho tôi (tôi đã sử dụng giải pháp của riêng mình, xem bên dưới) và việc thay đổi ứng dụng không phải là một tùy chọn ngay bây giờ. Nhưng tôi hy vọng nó sẽ giúp những người khác trong tương lai! Câu trả lời chính xác! – Pieter888

+0

addOnLayoutChangeListener chỉ được hỗ trợ từ Honeycomb. nó sẽ không hoạt động trên các API cũ. –

+0

Tôi có tọa độ ngay bây giờ - nhưng làm thế nào để vẽ trên đầu trang của một mảnh? – Skynet

0

Câu trả lời này bây giờ đã lỗi thời, Hãy tìm những câu trả lời được chấp nhận trên

tôi phát hiện ra rằng (tại thời điểm này) không có cách tìm ra các giá trị x/y của một mục trình đơn. Xem các mục menu cũng có thể được ẩn khỏi màn hình cho đến khi người dùng nhấn nút menu. Trong Android 3.0 trở lên, bạn có tùy chọn để triển khai thực đơn trong ứng dụng ActionBar của ứng dụng. Bạn có thể thêm nhiều mục menu trong thanh hành động, khi không còn vị trí nào để định vị một mục trên thanh, nó sẽ tạo ra nút "tràn" sẽ chứa tất cả các mục menu không thể đặt trên thanh hành động vì thiếu hụt không gian hoặc vì lập trình viên đặt rõ ràng mục menu xuất hiện trong menu mục bổ sung.

Tất cả hành vi này có thể là lý do tại sao các mục menu không có vị trí x/y của bạn mà bạn có thể truy xuất (hoặc đặt).

Cách cuối cùng tôi giải quyết vấn đề này là sử dụng hàm Paint.measureText() để xác định độ rộng của từng mục menu trong thanh tác vụ và sử dụng nó để tính toán độ lệch từ phía bên phải của màn hình. .

Đó là cách giải quyết nhưng nếu có ai gặp vấn đề tương tự như tôi, hãy biết rằng điều này chỉ hoạt động tốt. Chỉ cần nhớ đặt kích thước phông chữ thích hợp trên đối tượng Paint hoặc cách khác khi bạn đo chiều dài của văn bản, điều này có thể sẽ tính toán chiều rộng văn bản bằng cách sử dụng kích thước phông chữ khác với kích thước phông chữ của mục menu.

31

Tôi tìm thấy một cách khác để lấy móc trên nút thanh tác vụ, có thể đơn giản hơn một chút so với giải pháp được chấp nhận. Bạn chỉ cần gọi findViewById, với id của mục menu!

Bây giờ phần cứng là khi bạn có thể gọi điều này không? Trong số onCreateonResume, quá sớm. Cách tốt nhất để thực hiện việc này là sử dụng ViewTreeObserver của cửa sổ:

final ViewTreeObserver viewTreeObserver = getWindow().getDecorView().getViewTreeObserver(); 
    viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 
     @Override 
     public void onGlobalLayout() { 
      View menuButton = findViewById(R.id.menu_refresh); 
      // This could be called when the button is not there yet, so we must test for null 
      if (menuButton != null) { 
       // Found it! Do what you need with the button 
       int[] location = new int[2]; 
       menuButton.getLocationInWindow(location); 
       Log.d(TAG, "x=" + location[0] + " y=" + location[1]); 

       // Now you can get rid of this listener 
       viewTreeObserver.removeGlobalOnLayoutListener(this); 
      } 
     } 
    }); 

Điều này đi vào onCreate.

Lưu ý: điều này đã được thử nghiệm trên một dự án sử dụng ActionBarSherlock, vì vậy có thể nó không hoạt động với thanh tác vụ 'thực'.

+7

Tôi đề nghị thêm 'if (viewTreeObserver.isAlive())' kiểm tra trước khi loại bỏ người nghe vì đôi khi một ngoại lệ được ném nếu nó không còn sống. –

+0

Tuyệt vời! Cảm ơn bạn vì câu trả lời tuyệt vời này. Cái này phải đúng. – Cilenco

+0

findViewById - không hoạt động cho một mục menu? – Skynet

10

Chỉ cần xử lý các Menu Item như một view..like bình thường này:

View myActionView = findViewById(R.id.my_menu_item_id); 
    if (myActionView != null) { 
     int[] location = new int[2]; 
     myActionView.getLocationOnScreen(location); 

     int x = location[0]; 
     int y = location[1]; 
     Log.d(TAG, "menu item location --> " + x + "," + y); 
    } 

Lưu ý:Tôi đã thử nghiệm với hoạt động của tôi cấu hình sử dụng thanh công cụ, không trực tiếp như ActionBar ... nhưng tôi đoán nó sẽ hoạt động tương tự.

+0

Bạn thậm chí có thể gọi nó trong onOptionsItemSelected và nó sẽ hoạt động. – Simon

Các vấn đề liên quan