ActionItem的动画图标

Ale*_* Fu 91 android android-animation actionbarsherlock

我一直在寻找适合我问题的解决方案,但我似乎找不到一个.我有一个ActionBar(ActionBarSherlock),其菜单从XML文件中膨胀,该菜单包含一个项目,并且该项目显示为ActionItem.

菜单:

<menu xmlns:android="http://schemas.android.com/apk/res/android" >    
    <item
        android:id="@+id/menu_refresh"       
        android:icon="@drawable/ic_menu_refresh"
        android:showAsAction="ifRoom"
        android:title="Refresh"/>    
</menu>
Run Code Online (Sandbox Code Playgroud)

活动:

[...]
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getSupportMenuInflater().inflate(R.menu.mymenu, menu);
    return true;
  }
[...]
Run Code Online (Sandbox Code Playgroud)

ActionItem显示时带有图标而没有文本,但是当用户点击ActionItem时,我希望图标开始动画,更具体地说,是在适当的位置旋转.有问题的图标是刷新图标.

我意识到ActionBar支持使用自定义视图(添加动作视图)但是这个自定义视图被扩展为覆盖ActionBar的整个区域并且实际上阻止了除应用程序图标之外的所有内容,在我的情况下这不是我想要的.

所以我的下一次尝试是尝试使用AnimationDrawable并逐帧定义我的动画,将drawable设置为菜单项的图标,然后在onOptionsItemSelected(MenuItem item)获取图标并开始使用动画((AnimationDrawable)item.getIcon()).start().但这并不成功.有谁知道有任何方法来实现这种效果?

Jak*_*ton 173

你走在正确的轨道上.以下是GitHub Gaug.es应用程序将如何实现它.

首先,他们定义动画XML:

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="1000"
    android:interpolator="@android:anim/linear_interpolator" />
Run Code Online (Sandbox Code Playgroud)

现在定义操作视图的布局:

<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_action_refresh"
    style="@style/Widget.Sherlock.ActionButton" />
Run Code Online (Sandbox Code Playgroud)

我们需要做的就是在点击项目时启用此视图:

 public void refresh() {
     /* Attach a rotating ImageView to the refresh item as an ActionView */
     LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     ImageView iv = (ImageView) inflater.inflate(R.layout.refresh_action_view, null);

     Animation rotation = AnimationUtils.loadAnimation(getActivity(), R.anim.clockwise_refresh);
     rotation.setRepeatCount(Animation.INFINITE);
     iv.startAnimation(rotation);

     refreshItem.setActionView(iv);

     //TODO trigger loading
 }
Run Code Online (Sandbox Code Playgroud)

加载完成后,只需停止动画并清除视图:

public void completeRefresh() {
    refreshItem.getActionView().clearAnimation();
    refreshItem.setActionView(null);
}
Run Code Online (Sandbox Code Playgroud)

而且你已经完成了!

还有一些事要做:

  • 缓存动作视图布局通胀和动画通胀.它们很慢,所以你只想做一次.
  • 添加null签到completeRefresh()

这是应用程序上的pull请求:https://github.com/github/gauges-android/pull/13/files

  • 在执行此操作时,我也遇到了按钮跳到一边的问题.这是因为我没有使用Widget.Sherlock.ActionButton样式.我通过将`android:paddingLeft ="12dp"和`android:paddingRight ="12dp"添加到我自己的主题来纠正这个问题. (12认同)
  • @Alborz这完全是针对您的应用而非一般规则.这完全取决于您放置刷新方法的位置. (8认同)
  • 很好的答案,但getActivity()不再可访问,请改用getApplication(). (2认同)
  • 如果您的图像是方形且操作项的大小正确,则不应跳转. (2认同)

Mar*_*era 16

我使用ActionBarSherlock解决了一些问题,我想出了这个:

RES /布局/ indeterminate_progress_action.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="48dp"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:paddingRight="12dp" >

    <ProgressBar
        style="@style/Widget.Sherlock.ProgressBar"
        android:layout_width="44dp"
        android:layout_height="32dp"
        android:layout_gravity="left"
        android:layout_marginLeft="12dp"
        android:indeterminate="true"
        android:indeterminateDrawable="@drawable/rotation_refresh"
        android:paddingRight="12dp" />

</FrameLayout>
Run Code Online (Sandbox Code Playgroud)

RES /布局-V11/indeterminate_progress_action.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center" >

    <ProgressBar
        style="@style/Widget.Sherlock.ProgressBar"
        android:layout_width="32dp"
        android:layout_gravity="left"
        android:layout_marginRight="12dp"
        android:layout_marginLeft="12dp"
        android:layout_height="32dp"
        android:indeterminateDrawable="@drawable/rotation_refresh"
        android:indeterminate="true" />

</FrameLayout>
Run Code Online (Sandbox Code Playgroud)

RES /抽拉/ rotation_refresh.xml

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:pivotX="50%"
    android:pivotY="50%"
    android:drawable="@drawable/ic_menu_navigation_refresh"
    android:repeatCount="infinite" >

</rotate>
Run Code Online (Sandbox Code Playgroud)

活动中的代码(我在ActivityWithRefresh父类中有它)

// Helper methods
protected MenuItem refreshItem = null;  

protected void setRefreshItem(MenuItem item) {
    refreshItem = item;
}

protected void stopRefresh() {
    if (refreshItem != null) {
        refreshItem.setActionView(null);
    }
}

protected void runRefresh() {
    if (refreshItem != null) {
        refreshItem.setActionView(R.layout.indeterminate_progress_action);
    }
}
Run Code Online (Sandbox Code Playgroud)

在活动中创建菜单项

private static final int MENU_REFRESH = 1;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    menu.add(Menu.NONE, MENU_REFRESH, Menu.NONE, "Refresh data")
            .setIcon(R.drawable.ic_menu_navigation_refresh)
            .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS);
    setRefreshItem(menu.findItem(MENU_REFRESH));
    refreshData();
    return super.onCreateOptionsMenu(menu);
}

private void refreshData(){
    runRefresh();
    // work with your data
    // for animation to work properly, make AsyncTask to refresh your data
    // or delegate work anyhow to another thread
    // If you'll have work at UI thread, animation might not work at all
    stopRefresh();
}
Run Code Online (Sandbox Code Playgroud)

和图标,这是 drawable-xhdpi/ic_menu_navigation_refresh.png
可绘制-xhdpi/ic_menu_navigation_refresh.png

这可以在http://developer.android.com/design/downloads/index.html#action-bar-icon-pack中找到


Les*_*008 6

除了杰克沃顿所说的,你应该做以下工作,以确保动画平稳停止,在加载完成后不立即跳转.

首先,创建一个新的布尔值(对于整个类):

private boolean isCurrentlyLoading;
Run Code Online (Sandbox Code Playgroud)

找到开始加载的方法.活动开始加载时,将布尔值设置为true.

isCurrentlyLoading = true;
Run Code Online (Sandbox Code Playgroud)

找到加载完成时启动的方法.而不是清除动画,将布尔值设置为false.

isCurrentlyLoading = false;
Run Code Online (Sandbox Code Playgroud)

在动画上设置AnimationListener:

animationRotate.setAnimationListener(new AnimationListener() {
Run Code Online (Sandbox Code Playgroud)

然后,每次动画执行一次,这意味着当您的图标旋转一周时,检查加载状态,如果不再加载,动画将停止.

@Override
public void onAnimationRepeat(Animation animation) {
    if(!isCurrentlyLoading) {
        refreshItem.getActionView().clearAnimation();
        refreshItem.setActionView(null);
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,只有当动画已经旋转到结束并且将很快重复并且它不再加载时,才能停止动画.

这至少是我想要实现Jake的想法时所做的.