91

私は自分の問題に対する適切な解決策をどこでも探していましたが、まだ見つけられないようです。XML ファイルから拡張されたメニューを含む ActionBar (ActionBarSherlock) があり、そのメニューには 1 つの項目が含まれ、その 1 つの項目が 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>

アクティビティ:

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

ActionItem はアイコン付きでテキストなしで表示されますが、ユーザーが ActionItem をクリックすると、アイコンがアニメーションを開始し、より具体的にはその場で回転するようにします。問題のアイコンは更新アイコンです。

ActionBar はカスタム ビュー (アクション ビューの追加) の使用をサポートしていることに気付きましたが、このカスタム ビューは ActionBar の領域全体をカバーするように拡張され、実際にはアプリ アイコンを除くすべてをブロックします。 .

そこで私の次の試みは、AnimationDrawable を使用してアニメーションをフレームごとに定義し、ドローアブルをメニュー項目のアイコンとして設定してから、アイコンをonOptionsItemSelected(MenuItem item)取得して を使用してアニメーション化を開始すること((AnimationDrawable)item.getIcon()).start()でした。しかし、これは成功しませんでした。この効果を達成する方法を知っている人はいますか?

4

7 に答える 7

176

あなたは正しい軌道に乗っています。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" />

次に、アクション ビューのレイアウトを定義します。

<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" />

アイテムがクリックされるたびに、このビューを有効にするだけです。

 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
 }

読み込みが完了したら、アニメーションを停止してビューをクリアします。

public void completeRefresh() {
    refreshItem.getActionView().clearAnimation();
    refreshItem.setActionView(null);
}

そして、あなたは完了です!

追加の作業:

  • アクション ビュー レイアウト インフレーションとアニメーション インフレーションをキャッシュします。それらは遅いため、一度だけ実行する必要があります。
  • nullチェックインを追加completeRefresh()

アプリのプル リクエストは次のとおりです: https://github.com/github/gauges-android/pull/13/files

于 2012-03-16T05:09:53.797 に答える
16

I've worked a bit on solution using ActionBarSherlock, I've came up with this:

res/layout/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>

res/layout-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>

res/drawable/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>

Code in activity (I have it in ActivityWithRefresh parent class)

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

in activity creating menu items

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

And the icon, this is drawable-xhdpi/ic_menu_navigation_refresh.png
drawable-xhdpi/ic_menu_navigation_refresh.png

This could be found in http://developer.android.com/design/downloads/index.html#action-bar-icon-pack

于 2013-01-16T14:44:59.747 に答える
6

Jake Wharton が言ったことに加えて、ロードが終了するとすぐにアニメーションがスムーズに停止し、ジャンプしないように、次のことを行う必要があります。

最初に、(クラス全体に対して) 新しいブール値を作成します。

private boolean isCurrentlyLoading;

読み込みを開始するメソッドを見つけます。アクティビティの読み込みが開始されたら、ブール値を true に設定します。

isCurrentlyLoading = true;

読み込みが完了したときに開始されるメソッドを見つけます。アニメーションをクリアする代わりに、ブール値を false に設定します。

isCurrentlyLoading = false;

アニメーションに AnimationListener を設定します。

animationRotate.setAnimationListener(new AnimationListener() {

次に、アニメーションが 1 回実行されるたびに、つまりアイコンが 1 回転したときに読み込み状態を確認し、それ以上読み込まれなければアニメーションが停止します。

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

このように、アニメーションが最後まで回転し、すぐに繰り返され、それ以上ロードされない場合にのみ、アニメーションを停止できます。

これは少なくとも、Jake のアイデアを実装したいと思ったときに私がしたことです。

于 2014-02-19T16:08:54.983 に答える
1

コードでローテーションを作成するオプションもあります。完全なスニップ:

    MenuItem item = getToolbar().getMenu().findItem(Menu.FIRST);
    if (item == null) return;

    // define the animation for rotation
    Animation animation = new RotateAnimation(0.0f, 360.0f,
            Animation.RELATIVE_TO_SELF, 0.5f,
            Animation.RELATIVE_TO_SELF, 0.5f);
    animation.setDuration(1000);
    //animRotate = AnimationUtils.loadAnimation(this, R.anim.rotation);

    animation.setRepeatCount(Animation.INFINITE);

    ImageView imageView = new ImageView(this);
    imageView.setImageDrawable(UIHelper.getIcon(this, MMEXIconFont.Icon.mmx_refresh));

    imageView.startAnimation(animation);
    item.setActionView(imageView);
于 2016-08-27T14:37:26.487 に答える
0

私の非常に単純なソリューション(たとえば、リファクタリングが必要)は、標準のMenuItemで動作し、任意の数の状態、アイコン、アニメーション、ロジックなどで使用できます.

アクティビティ クラス:

private enum RefreshMode {update, actual, outdated} 

標準リスナー:

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.menu_refresh: {
            refreshData(null);
            break;
        }
    }
}

refreshData() に次のようにします。

setRefreshIcon(RefreshMode.update);
// update your data
setRefreshIcon(RefreshMode.actual);

アイコンの色またはアニメーションを定義するメソッド:

 void setRefreshIcon(RefreshMode refreshMode) {

    LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    Animation rotation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.rotation);
    FrameLayout iconView;

    switch (refreshMode) {
        case update: {
            iconView = (FrameLayout) inflater.inflate(R.layout.refresh_action_view,null);
            iconView.startAnimation(rotation);
            toolbar.getMenu().findItem(R.id.menu_refresh).setActionView(iconView);
            break;
        }
        case actual: {
            toolbar.getMenu().findItem(R.id.menu_refresh).getActionView().clearAnimation();
            iconView = (FrameLayout) inflater.inflate(R.layout.refresh_action_view_actual,null);
            toolbar.getMenu().findItem(R.id.menu_refresh).setActionView(null);
            toolbar.getMenu().findItem(R.id.menu_refresh).setIcon(R.drawable.ic_refresh_24dp_actual);
            break;
        }
        case outdated:{
            toolbar.getMenu().findItem(R.id.menu_refresh).setIcon(R.drawable.ic_refresh_24dp);
            break;
        }
        default: {
        }
    }
}

アイコン付きの2つのレイアウトがあります (R.layout.refresh_action_view (+ "_actual") ):

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="48dp"
    android:layout_height="48dp"
    android:gravity="center">
<ImageView
    android:src="@drawable/ic_refresh_24dp_actual" // or ="@drawable/ic_refresh_24dp"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:layout_margin="12dp"/>
</FrameLayout>

この場合の標準回転アニメーション (R.anim.rotation) :

<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:repeatCount="infinite"
/>
于 2018-12-20T16:29:00.833 に答える