Как получить текущее местоположение элемента ActionBar MenuItem?

Я хочу показать небольшую информационную метку под MenuItem в ActionBar приложения. Чтобы правильно установить это положение, мне нужно знать x-позицию MenuItem .

Google пока не принес мне никаких полезных результатов.

Возможно ли это?

Solutions Collecting From Web of "Как получить текущее местоположение элемента ActionBar MenuItem?"

Я наконец нашел ответ на это! Это немного хаки, но не слишком много. Единственными минусами являются:

  1. Он использует API 3.0+. Серьезно, хотя Google, какой смысл выпускать новые версии Android, если мы не сможем их использовать? / Декламация.
  2. Вы должны заменить MenuItem на свой собственный View . ImageView довольно похож на стандартный, но он пропускает функции, такие как длительное нажатие, чтобы увидеть подсказку и, возможно, другие вещи.
  3. Я его не тестировал.

Хорошо, вот как мы это делаем. Измените действие onCreateOptionsMenu() на вашей Activity следующим образом:

 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; } 

И тогда у вас есть функция, которая обновляет ваш полезный вид инструкций с указанием местоположения кнопки и перерисовывает ее:

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

Наконец, сделайте свой необычный пользовательский вид, который рисует стрелку (рядом) с кнопкой. В методе onDraw вы можете преобразовать координаты экрана обратно в координаты Canvas используя ту же функцию getLocationOnScreen . Что-то вроде этого:

 @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); } 

(Но, очевидно, вам нужно скопировать целевое местоположение с размером холста). Если вы идете по тому же методу, что и Google, на котором вы просматриваете представление по всему экрану, вам не придется беспокоиться об этом, но это более навязчиво. Метод Google определенно не использует никаких частных API (удивительно). Проверьте Cling.java в коде Launcher2.

Кстати, если вы посмотрите на источник подобной реализации Google для этой программы для запуска (они почему-то называют экран инструкций Cling ), вы можете увидеть, что он еще более взломан. Они в основном используют абсолютные позиции экрана, определяемые использованием макета.

Надеюсь, это поможет людям!

Я нашел другой способ получить крючок на кнопке панели действий, которая может быть немного проще, чем принятое решение. Вы можете просто вызвать findViewById с идентификатором элемента меню!

Теперь тяжелая часть – когда вы можете это назвать? В onCreate и onResume это слишком рано. Ну, один из способов сделать это – использовать ViewTreeObserver окна:

  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); } } }); 

Это происходит в onCreate .

Примечание: это было протестировано в проекте с помощью ActionBarSherlock, поэтому возможно, что он не работает с «реальной» панелью действий.

Просто обрабатывайте пункт меню как обычный вид … например:

  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); } 

Примечание. Я тестировал свою активность, настроенную с помощью ToolBar, а не непосредственно как ActionBar … но я думаю, что она должна работать аналогичным образом.

Этот ответ теперь устарел, ищите принятый ответ выше

Я узнал, что (в это время) нет способа узнать значение x / y для элемента меню. См. Пункты меню также можно скрыть от экрана, пока пользователь не нажмет кнопку меню. В Android 3.0 и выше у вас есть возможность реализовать меню в ActionBar приложения. Вы можете добавить много элементов меню в панель действий, когда больше нет места для позиционирования элемента на панели, он просто создаст кнопку «Переполнение», которая будет содержать все пункты меню, которые нельзя было бы разместить на панели действий, потому что Нехватки места или из-за того, что программист явно установил пункт меню в меню переполнения.

Возможно, все это связано с тем, что элементы меню не имеют своей позиции x / y, которую вы можете получить (или установить).

Как я в конечном итоге решил эту проблему, воспользовавшись Paint.measureText() чтобы определить, насколько широким будет каждый элемент меню на панели действий, и использовать его для вычисления смещения с правой стороны экрана, где должна быть метка ,

Это обходной путь, но если у кого-либо есть такая же проблема, как и я, знайте, что это работает отлично. Не забудьте установить соответствующий размер шрифта в объекте Paint а также при измерении длины текста он, скорее всего, рассчитает ширину текста с использованием другого размера шрифта, чем размер шрифта вашего меню.