有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

导航抽屉上的java动画在所有设备上都不平滑

我的应用程序中有一个导航抽屉,带有以下控件:

1)图像视图和进度条 2) ImageView和ProgressBar下面的ListView

此列表中的每个元素都在抽屉打开时设置动画,我将按如下方式设置Listview元素的动画:

public View getView(int position, View convertView, ViewGroup parent) {



        if (convertView == null) {
            LayoutInflater mInflater = (LayoutInflater)context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
            convertView = mInflater.inflate(R.layout.drawer_list_item, null);
        }


        ImageView imgIcon = (ImageView) convertView.findViewById(R.id.icon);
        TextView txtTitle = (TextView) convertView.findViewById(R.id.title);
        TextView txtCount = (TextView) convertView.findViewById(R.id.counter);

        AnimatorSet sunSet = (AnimatorSet) AnimatorInflater.loadAnimator(MainActivity.con, R.animator.sun_swing);
        AnimatorSet wheelSet = (AnimatorSet) AnimatorInflater.loadAnimator(MainActivity.con, R.animator.wheel_spin);
        //set the view as target
        sunSet.setTarget(imgIcon);
        //start the animation
        sunSet.start();

        wheelSet.setTarget(imgIcon);
        //start the animation
        wheelSet.start();


        ObjectAnimator textAnim2 = ObjectAnimator.ofFloat(txtTitle, "x",convertView.getWidth()-(txtTitle.getWidth()/2), (convertView.getWidth()/2)-70);

        textAnim2.setDuration(1000);
        textAnim2.setRepeatCount(0);
        textAnim2.start();

        txtTitle.setTypeface(tf); 
        txtTitle.setTextSize(18);

        imgIcon.setImageResource(navDrawerItems.get(position).getIcon());    
        txtTitle.setText(navDrawerItems.get(position).getTitle());
        //convertView.startAnimation(getMaximAnim());

        if(navDrawerItems.get(position).getCounterVisibility()){
            txtCount.setText(navDrawerItems.get(position).getCount());
        }else{
            // hide the counter view
            txtCount.setVisibility(View.GONE);
        }

        return convertView;
    }

这是我的车轮旋转:

<set xmlns:安卓="http://schemas.安卓.com/apk/res/安卓"
    安卓:interpolator="@安卓:anim/accelerate_decelerate_interpolator"
    安卓:ordering="sequentially" >

    <objectAnimator
        安卓:duration="1000"
        安卓:propertyName="rotation"
        安卓:repeatCount="0"
        安卓:repeatMode="reverse"
        安卓:valueFrom="100"
        安卓:valueTo="0"
        安卓:valueType="floatType" />

</set>

这是我的太阳秋千:

<set xmlns:安卓="http://schemas.安卓.com/apk/res/安卓"
    安卓:interpolator="@安卓:anim/accelerate_decelerate_interpolator"
    安卓:ordering="sequentially" >

    <objectAnimator
        安卓:duration="1000"
        安卓:propertyName="x"
        安卓:repeatCount="0"
        安卓:valueFrom="230"
        安卓:valueTo="20"
        安卓:valueType="floatType" />

</set>

在舱单中:

<application
        安卓:allowBackup="true"
        安卓:hardwareAccelerated="true"
        安卓:icon="@drawable/ic_launcher"
        安卓:label="@string/app_name"
        安卓:theme="@style/CustomActionBarTheme" >

在onDrawerOpen

runOnUiThread(run);

我的跑步路线是:

final Runnable run = new Runnable(){
            public void run(){
                //reload content


                adapter.notifyDataSetChanged();
                mDrawerList.invalidateViews();
                mDrawerList.refreshDrawableState();

            }
        };

我这样做是为了在打开导航抽屉时始终获得动画。我发现我的动画在大多数手机上都能正常工作,但是一些介于4.0和4.4之间的手机在不停地运行动画。可能的原因是什么?如何避免/克服

这是导航抽屉打开和关闭调用之间的跟踪:

enter image description here

编辑2:我已经从下面的SGal答案中实现了很多,我的更新代码如下所示:

 public class NavDrawerListAdapter extends BaseAdapter {




    private Context context;
    private ArrayList<NavDrawerItem> navDrawerItems;
    String fontPath = "fonts/HelveticaNeue-Light.otf";
    Typeface tf; 
    ObjectAnimator textAnim2;
    ObjectAnimator spin;
    ObjectAnimator swing;




    public NavDrawerListAdapter(Context context, ArrayList<NavDrawerItem> navDrawerItems){
        this.context = context;
        this.navDrawerItems = navDrawerItems;
        tf = Typeface.createFromAsset(context.getAssets(), fontPath);

    }

    @Override
    public int getCount() {
        return navDrawerItems.size();
    }

    @Override
    public Object getItem(int position) {       
        return navDrawerItems.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        System.out.println("Position: "+position);
        ViewHolder viewHolder = new ViewHolder();

        if (convertView == null) {

            LayoutInflater mInflater = (LayoutInflater)context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
            convertView = mInflater.inflate(R.layout.drawer_list_item, null);
            viewHolder.imgIcon = (ImageView) convertView.findViewById(R.id.icon);
            viewHolder.txtTitle = (TextView) convertView.findViewById(R.id.title);
            viewHolder.txtCount = (TextView) convertView.findViewById(R.id.counter);
            convertView.setTag(viewHolder);



        }

        viewHolder = (ViewHolder) convertView.getTag();
        //  if(position == 0){
        textAnim2 = ObjectAnimator.ofFloat(viewHolder.txtTitle, "x",convertView.getWidth()-(viewHolder.txtTitle.getWidth()/2), ((viewHolder.imgIcon.getWidth())+30));
        textAnim2.setDuration(1000);
        textAnim2.setRepeatCount(0);

        spin = ObjectAnimator.ofFloat(viewHolder.imgIcon, "rotation", 70f , 0f);
        spin.setDuration(1000);
        spin.setRepeatCount(0);

        swing = ObjectAnimator.ofFloat(viewHolder.imgIcon, "x",convertView.getWidth()-(viewHolder.txtTitle.getWidth()+80), 30);
        swing.setDuration(1000);
        swing.setRepeatCount(0);

        /*  }else if(position == 1){
            textAnim2 = ObjectAnimator.ofFloat(viewHolder.txtTitle, "x",convertView.getWidth()-(viewHolder.txtTitle.getWidth()/2), ((viewHolder.imgIcon.getWidth())+30));
            textAnim2.setDuration(1000);
            textAnim2.setRepeatCount(0);

            spin = ObjectAnimator.ofFloat(viewHolder.imgIcon, "rotation", 70f , 0f);
            spin.setDuration(1000);
            spin.setRepeatCount(0);

            swing = ObjectAnimator.ofFloat(viewHolder.imgIcon, "x",convertView.getWidth()-(viewHolder.txtTitle.getWidth()+120), 30);
            swing.setDuration(1000);
            swing.setRepeatCount(0);
        }else if(position == 2){
            textAnim2 = ObjectAnimator.ofFloat(viewHolder.txtTitle, "x",convertView.getWidth()-(viewHolder.txtTitle.getWidth()/2), ((viewHolder.imgIcon.getWidth())+30));
            textAnim2.setDuration(1000);
            textAnim2.setRepeatCount(0);

            spin = ObjectAnimator.ofFloat(viewHolder.imgIcon, "rotation", 70f , 0f);
            spin.setDuration(1000);
            spin.setRepeatCount(0);

            swing = ObjectAnimator.ofFloat(viewHolder.imgIcon, "x",convertView.getWidth()-(viewHolder.txtTitle.getWidth()+140), 30);
            swing.setDuration(1000);
            swing.setRepeatCount(0);
        } */


        swing.start();
        textAnim2.start();
        spin.start();




        viewHolder.txtTitle.setTypeface(tf); 
        viewHolder.txtTitle.setTextSize(18);

        viewHolder.imgIcon.setImageResource(navDrawerItems.get(position).getIcon());    
        viewHolder.txtTitle.setText(navDrawerItems.get(position).getTitle());

        if(navDrawerItems.get(position).getCounterVisibility()){
            viewHolder.txtCount.setText(navDrawerItems.get(position).getCount());
        }else{
            viewHolder.txtCount.setVisibility(View.GONE);
        }

        return convertView;
    }

    static class ViewHolder {
        ImageView imgIcon;
        TextView txtTitle;
        TextView txtCount;
    }

共 (1) 个答案

  1. # 1 楼答案

    首先findViewById很昂贵,这就是为什么使用ViewHolder模式总是一个好主意

    其次,在每次getView()调用中都要进行两次xml动画膨胀。XML膨胀是更昂贵的操作

    考虑像这样重写GETVIEW方法。将Animator inflation移动到适配器构造函数,并在getView()中重用它们,还添加了一个viewHolder以提高列表滚动性能(如果菜单列表很长,则很有用):

    private Activity ctx;
    private AnimatorSet sunSet;
    private AnimatorSet wheelSet;
    
    public MyAdapter(Activity ctx){
        this.ctx = ctx;
        this.sunSet = (AnimatorSet) AnimatorInflater.loadAnimator(ctx, R.animator.sun_swing);
        this.wheelSet = (AnimatorSet) AnimatorInflater.loadAnimator(ctx, R.animator.wheel_spin);
    }
    
    public View getView(int position, View convertView, ViewGroup parent) {
    
        ViewHolder viewHolder = new ViewHolder();
    
        if (convertView == null) {
            convertView = ctx.getLayoutInflater().inflate(R.layout.drawer_list_item, parent, false);
    
            viewHolder.imgIcon = (ImageView) convertView.findViewById(R.id.icon);
            viewHolder.txtTitle = (TextView) convertView.findViewById(R.id.title);
            viewHolder.txtCount = (TextView) convertView.findViewById(R.id.counter);
            convertView.setTag(viewHolder);
        }
    
        viewHolder = (ViewHolderItem) convertView.getTag();
    
        AnimatorSet sunSetClone = sunSet.clone();
        sunSetClone.setTarget(viewHolder.imgIcon);
        sunSetClone.start();
    
        AnimatorSet wheelSetClone = wheelSet.clone();
        wheelSetClone.setTarget(viewHolder.imgIcon);
        wheelSetClone.start();
    
        ObjectAnimator textAnim2 = ObjectAnimator.ofFloat(viewHolder.txtTitle, "x",convertView.getWidth()-(viewHolder.txtTitle.getWidth()/2), (convertView.getWidth()/2)-70);
    
        textAnim2.setDuration(1000);
        textAnim2.setRepeatCount(0);
        textAnim2.start();
    
        viewHolder.txtTitle.setTypeface(tf); 
        viewHolder.txtTitle.setTextSize(18);
    
        viewHolder.imgIcon.setImageResource(navDrawerItems.get(position).getIcon());    
        viewHolder.txtTitle.setText(navDrawerItems.get(position).getTitle());
    
        if(navDrawerItems.get(position).getCounterVisibility()){
            viewHolder.txtCount.setText(navDrawerItems.get(position).getCount());
        }else{
            viewHolder.txtCount.setVisibility(View.GONE);
        }
    
        return convertView;
    }
    
    static class ViewHolder {
        ImageView imgIcon;
        TextView txtTitle;
        TextView txtCount;
    }
    

    您可以添加的另一个性能改进是imageView.setImageResource(navDrawerItems.get(position).getIcon()); 正如Android documentation所述:

    setImageResource: This does Bitmap reading and decoding on the UI thread, which can cause a latency hiccup. If that's a concern, consider using setImageDrawable(android.graphics.drawable.Drawable) or setImageBitmap(android.graphics.Bitmap) and BitmapFactory instead.

    我个人喜欢用AsyncDrawable

    编辑:刚刚意识到它只会为一个列表项设置动画,因为我们总是覆盖目标视图。幸运的是,AnimatorSet将clone()实现为“深度复制”,即使克隆正在运行的动画,也会重置所有值,因此我更新了代码,而不是:

        sunSet.reset();
        sunSet.setTarget(viewHolder.imgIcon);
        sunSet.start();
    
        wheelSet.reset();
        wheelSet.setTarget(viewHolder.imgIcon);
        wheelSet.start();
    

    要做到这一点:

        AnimatorSet sunSetClone = sunSet.clone();
        sunSetClone.setTarget(viewHolder.imgIcon);
        sunSetClone.start();
    
        AnimatorSet wheelSetClone = wheelSet.clone();
        wheelSetClone.setTarget(viewHolder.imgIcon);
        wheelSetClone.start();
    

    克隆仍然比XML膨胀快得多