[英]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:这似乎不是使AnimationDrawable
在MenuItem
上工作的可行解决方案。 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.