public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: return true; case R.id.searchIcon: return true; case R.id.startRefresh: refreshItem = item; refresh(); return true; case R.id.stopRefresh: if (refreshItem != null && refreshItem.getActionView() != null) { refreshItem.getActionView().clearAnimation(); refreshItem.setActionView(null); } return true; default: return super.onOptionsItemSelected(item); } } public void refresh() { if (FeedActivity.this != null) { /* * Attach a rotating ImageView to the refresh item as an ActionView */ LayoutInflater inflater = (LayoutInflater) FeedActivity.this .getSystemService(Context.LAYOUT_INFLATER_SERVICE); ImageView iv = (ImageView) inflater.inflate( R.layout.refresh_action_view, null); Animation rotation = AnimationUtils.loadAnimation( FeedActivity.this, R.anim.clockwise_refresh); rotation.setRepeatCount(Animation.INFINITE); iv.startAnimation(rotation); refreshItem.setActionView(iv); } }
Перед нажатием:
После нажатия:
Здесь значок анимируется (вращается).
Проблема:
Почему он смещается влево?
Как только он сдвинется влево, значок становится неактивным и, как ни странно, кнопка возврата устройства также не работает
РЕДАКТИРОВАТЬ:
В комментариях ниже этого ответа:
Анимированная иконка для ActionItem
Джейк Уортон говорит, что если вы используете квадратный и правильный размер значка для пункта меню, вы не получите это странное поведение, кому-то, у кого такая же проблема.
Но я использую 32×32 изображение на устройстве, которое использует mdpi drawables. Что, как указано, должно работать 🙁
Спасибо
РЕДАКТИРОВАТЬ:
refresh_action_view.xml
<?xml version="1.0" encoding="utf-8"?> <ImageView xmlns:android="http://schemas.android.com/apk/res/android" style="@style/Widget.Sherlock.ActionButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_refresh" />
Пользовательский стиль, который я использую в своем приложении
<style name="My_solid_ActionBar" parent="@style/Widget.Sherlock.Light.ActionBar.Solid.Inverse"> <item name="background">@drawable/ab_solid_My</item> <item name="backgroundStacked">@drawable/ab_stacked_solid_My</item> <item name="backgroundSplit">@drawable/ab_bottom_solid_My</item> <item name="progressBarStyle">@style/My_ProgressBar</item> <item name="android:background">@drawable/ab_solid_My</item> <item name="android:backgroundStacked">@drawable/ab_stacked_solid_My</item> <item name="android:backgroundSplit">@drawable/ab_bottom_solid_My</item> <item name="android:progressBarStyle">@style/My_ProgressBar</item> </style>
Проблема в том, что вы не обрабатываете все onCreateOptionsMenu()
меню в onCreateOptionsMenu()
. Базовая логика анимации обновления ActionBar
которую я видел в приложениях с открытым исходным кодом, например Andlytics (а также я использовал себя в проектах), заключается в реализации boolean
флага в onCreateOptionsMenu()
чтобы решить, показывать ли анимацию обновления.
Вы можете реализовать его следующим образом: Когда вы вызываете метод refresh()
, он устанавливает для boolean
флаг isRefreshing
значение true и вызывает inValidateOptionsMenu()
который «за сценой» вызывает onCreateOptionsMenu()
чтобы запустить анимацию:
onCreateOptionsMenu(...)
меню в onCreateOptionsMenu(...)
:
@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { menu.clear(); super.onCreateOptionsMenu(menu, inflater); //inflate a menu which shows the non-animated refresh icon inflater.inflate(R.menu.my_ab_menu, menu); if (isRefreshing) { //if we're refreshing, show the animation MenuItem item = menu.findItem(R.id.refreshMenuItem); item.setActionView(R.layout.action_bar_indeterminate_progress); ImageView iv = (ImageView) item.getActionView().findViewById(R.id.loadingImageView); ((AnimationDrawable) iv.getDrawable()).start(); } }
Начните анимацию так:
public void refresh(){ isRefreshing = true; inValidateOptionsMenu(); }
Если вы хотите, чтобы пользователь начал анимацию, когда он onOptionsItemSelected()
значок обновления, сделайте это в onOptionsItemSelected()
:
case R.id.refreshMenuItem: isRefreshing = true; item.setActionView(R.layout.action_bar_indeterminate_progress); ImageView iv = (ImageView) item.getActionView().findViewById(R.id.loadingImageView); ((AnimationDrawable) iv.getDrawable()).start(); //...
Чтобы остановить анимационный вызов:
isRefreshing = false; invalidateOptionsMenu();
Этот код из Fragment
поэтому вам может потребоваться настроить, если для Activity
, но я думаю, что он передает основную идею.
Я попробовал тот же самый код, который вы используете, и он отлично подходит для меня. Единственное, что может быть иначе, это две вещи:
1) макет refresh_action_view (здесь для сравнения):
<?xml version="1.0" encoding="utf-8"?> <ImageView xmlns:android="http://schemas.android.com/apk/res/android" style="?attr/actionButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_menu_refresh" />
2) Параметры отображения вашей панели действий (вот мой стиль. Xml для сравнения).
<resources> <style name="AppTheme" parent="Theme.Sherlock.Light.DarkActionBar"> <item name="android:actionBarStyle">@style/Widget.ActionBar</item> <item name="actionBarStyle">@style/Widget.ActionBar</item> </style> <style name="Widget.ActionBar" parent="Widget.Sherlock.Light.ActionBar.Solid.Inverse"> <item name="android:displayOptions">showHome|useLogo|showCustom</item> <item name="displayOptions">showHome|useLogo|showCustom</item> </style> </resources>
Можете ли вы поделиться своим?