简体   繁体   English

Android DrawerLayout 图标 animation

[英]Android DrawerLayout icon animation

I'm trying to animate the icons in my DrawerLayout using an AnimationDrawable .我正在尝试使用 AnimationDrawable 为我的DrawerLayout中的图标设置AnimationDrawable I created a new project selecting Navigation Drawer Activity as the main activity.我创建了一个新项目,选择 Navigation Drawer Activity 作为主要活动。 I created an animation from a set of XML files and the animation runs in the previewer in Android Studio.我从一组 XML 文件创建了一个 animation,animation 在 Android Studio 的预览器中运行。 I set the animation XML as the icon on the menu item and add a DrawerListener.onDrawerOpened(View V) that gets the menu item, gets its icon and calls start() as described here https://developer.android.com/guide/topics/graphics/drawable-animation .我将 animation XML 设置为菜单项上的图标,并添加一个DrawerListener.onDrawerOpened(View V)获取菜单项,获取其图标并调用 start() ,如此处所述https://developer.android.com/guide /topics/graphics/drawable-animation This seemed pretty straightforward to implement but also too simple which is why I wasn't too surprised when it didn't work.这看起来很容易实现,但也太简单了,这就是为什么当它不起作用时我并不太惊讶。 It just shows the first image in the series and never changes to the other images.它只显示系列中的第一张图片,从不更改其他图片。 If I run the app in the debugger I see that the icon is indeed an AnimationDrawable and that the icon's instance variables mAnimating and mRunning change from false to true when I call start() on it.如果我在调试器中运行该应用程序,我会看到该图标确实是一个 AnimationDrawable,并且当我对其调用 start() 时,该图标的实例变量 mAnimating 和 mRunning 从 false 变为 true。 Obviously there is something more I need to be doing but I don't know what.显然我还需要做一些事情,但我不知道是什么。 I did notice that the icon's mAnimationRunnable is set to null and I'm guessing this might have something to do with it.我确实注意到图标的 mAnimationRunnable 设置为 null,我猜这可能与它有关。

Animation ld.xml Animation ld.xml

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
    <item android:drawable="@drawable/ic_untitled_1" android:duration="500" />
    <item android:drawable="@drawable/ic_untitled_2" android:duration="500" />
    <item android:drawable="@drawable/ic_untitled_3" android:duration="500" />
    <item android:drawable="@drawable/ic_untitled_4" android:duration="500" />
    <item android:drawable="@drawable/ic_untitled_5" android:duration="500" />
    <item android:drawable="@drawable/ic_untitled_6" android:duration="500" />
    <item android:drawable="@drawable/ic_untitled_7" android:duration="500" />
    <item android:drawable="@drawable/ic_untitled_8" android:duration="500" />
</animation-list>

Drawer activity_main_drawer.xml抽屉activity_main_drawer.xml _main_drawer.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:showIn="navigation_view">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/nav_home"
            android:icon="@drawable/ld"
            android:title="@string/menu_home" />
        <item
            android:id="@+id/nav_settings"
            android:icon="@drawable/ic_menu_gallery"
            android:title="@string/menu_settings" />
        <item
            android:id="@+id/nav_timers"
            android:icon="@drawable/ic_menu_slideshow"
            android:title="@string/menu_timers" />
    </group>
</menu>

Main layout activity_main.xml主布局activity_main.xml

<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        android:id="@+id/app_bar_main"
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>

Main activity onCreate MainActivity.java主活动 onCreate MainActivity.java

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        com.company.databinding.ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        setSupportActionBar(binding.appBarMain.toolbar);

        DrawerLayout drawer = binding.drawerLayout;
        NavigationView navigationView = binding.navView;

        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        mAppBarConfiguration = new AppBarConfiguration.Builder(R.id.nav_home, R.id.nav_settings, R.id.nav_timers).setOpenableLayout(drawer).build();
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
        NavigationUI.setupWithNavController(navigationView, navController);

        binding.drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
            @Override
            public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
            }

            @Override
            public void onDrawerOpened(View drawerView) {
              ((AnimationDrawable)navigationView.getMenu().getItem(0).getIcon()).start();
            }

            @Override
            public void onDrawerClosed(@NonNull View drawerView) {
               ((AnimationDrawable)navigationView.getMenu().getItem(0).getIcon()).stop();
            }

            @Override
            public void onDrawerStateChanged(int newState) {
            }
        });
    }

I haven't been able to make the AnimationDrawable start() as a menu icon but it does start if I display it in an ImageView in the navigation header. So I manually animated it myself.我无法将AnimationDrawable start()作为菜单图标,但如果我在导航 header 中的ImageView中显示它,它就会启动。所以我自己手动设置动画。 Here is my MenuIconAnimator class. I still use a DrawerListener and in onDrawerOpened(View drawerView) I create an instance of my animator class passing it the menu item and then I call start() on it.这是我的MenuIconAnimator class。我仍然使用DrawerListener并在onDrawerOpened(View drawerView)中创建我的动画师 class 的实例,将菜单项传递给它,然后我在其上调用 start()。 This swaps the menu icon based on the parameters setup in the animation XML. And then in onDrawerClosed(@NonNull View drawerView) I call the method stopThread() on the MenuIconAnimator and the thread stops.这根据 animation XML 中设置的参数交换菜单图标。然后在onDrawerClosed(@NonNull View drawerView)中,我调用 MenuIconAnimator 上的方法MenuIconAnimator stopThread()并且线程停止。

Here are the relevant DrawerListener methods.下面是相关的DrawerListener方法。 menuIconAnimator is an instance variable on my activity class. menuIconAnimator是我的活动 class 上的一个实例变量。

            @Override
            public void onDrawerOpened(View drawerView) {
                menuIconAnimator = new MenuIconAnimator(navigationView.getMenu().getItem(0));
                menuIconAnimator.start();
            }

            @Override
            public void onDrawerClosed(@NonNull View drawerView) {
                menuIconAnimator.stopThread();
            }

Here is my MenuIconAnimator class.这是我的MenuIconAnimator class。

package com.leridiandynamics.smartrecirculationcontrol2.ui;

import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.view.MenuItem;

public class MenuIconAnimator extends Thread{
    Boolean running=true;
    MenuItem menuItem;

    public MenuIconAnimator(MenuItem menuItem){
        this.menuItem = menuItem;
    }

    public void stopThread(){
        running = false;
    }

    public void run() {
        // Get the icon that is set on the menuItem. This is an AnimationDrawable.
        // Hold onto it while we manually animate each frame by setting the frame
        // drawable as the menuItem icon. 
        AnimationDrawable animationDrawable = ((AnimationDrawable)menuItem.getIcon());
        Handler mainHandler = new Handler(Looper.getMainLooper());
        while (running) {
            try {
                // loop through each frame setting it as the icon on the menu item and then sleep 
                // the thread for the duration of the frame. 
                for (int i=0; i<animationDrawable.getNumberOfFrames();i++){
                    Drawable drawable = animationDrawable.getFrame(i);
                    mainHandler.post(() -> menuItem.setIcon(drawable));
                    sleep(animationDrawable.getDuration(i));
                    if (!running) break;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // restore the original animationDrawable on the menuItem so it is available the next time 
        // the MenuIconAnimator is called.
        mainHandler.post(() -> menuItem.setIcon(animationDrawable));
    }
}

UPDATE: It seems that if you have the animation running too quickly the menu is not very responsive to user input.更新:似乎如果 animation 运行得太快,菜单对用户输入的响应不是很好。 Maybe that is why animation doesn't work on the menu items out of the box.也许这就是为什么 animation 对开箱即用的菜单项不起作用的原因。

UPDATE 2: I have discovered that if the menu item's icon is changed while the user is tapping the menu item, the tap does not register.更新 2:我发现如果在用户点击菜单项时更改了菜单项的图标,则点击不会注册。 Finger touch, icon change, finger release...the menu item selection does not register.手指触摸、图标更改、手指松开...菜单项选择未注册。

UPDATE 3: This does not appear to be a viable solution to making AnimationDrawable work on a MenuItem .更新 3:这似乎不是使AnimationDrawableMenuItem上工作的可行解决方案。 When the icon is changed the entire menu appears to redraw and any touch events are reset.更改图标时,整个菜单似乎会重绘,并且所有触摸事件都会重置。 I submitted an issue with Google regarding AnimationDrawable not animating on a MenuItem .我向 Google 提交了一个关于AnimationDrawable没有在MenuItem上设置动画的问题。 https://issuetracker.google.com/issues/226640828 Will see if this gets addressed. https://issuetracker.google.com/issues/226640828看看这个问题是否得到解决。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM