如何在listview执行RequestLayout()时制作流畅的动画

时间:2015-08-04 04:05:53

标签: android listview animation

我在按钮上实现旋转动画,效果很好。

当我把它放在操作栏上时,然后在RequestLayout()上的窗口调用ListView的内容中,动画开始丢帧。

由于RequestLayout()将挂起主线程,因此它有两个解决方案:

  1. 逐行手动更新ListView,每40ms释放一次主线程
  2. 找到“高优先级”动画,即使主线程忙,也可以继续播放
  3. 虽然第一个解决方案值得尝试,但我不知道如何实施第二个解决方案。

    希望得到你的建议。 ;)

    在我的实际项目中,动画是一个简单的旋转动画:

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/linear_interpolator">
    <rotate 
        android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="50%"
        android:pivotY="50%"
        android:duration="500" /> 
    
    </set>
    

    下面的代码是我用来测试ListView的演示。虽然它与上面的动画无关,但是当我更新ListView的数据时,我可以通过手机提供的GPU开发工具看到android开始丢帧。

    在实际项目中,当listview的数据正在更新时,动画会显得滞后。

    MainActivity:

    public class MainActivity extends Activity {
    
    
    public static int N_ROW = 200;
    
        private ListView mListView;
        private ArrayList<String> mData1 = null;
        private ArrayList<String> mData2 = null;
        private ArrayList<String> mData3 = null;
        private int mCurrData = 1;
        private Random r = new Random();
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mListView = (ListView) findViewById(R.id.listView);
    
            /// random, 3-digits test data to display in listview
            mData1 = genRandomData(0);
    
            /// longer test data 
            mData2 = genRandomData(100000);
    
            /// another test data to change content of textView but do not change the content length
            mData3 = genRandomData(0);
    
            final ListViewAdapter adapter = new ListViewAdapter(this, R.layout.list_item_name, mData1);
            mListView.setAdapter(adapter);
    
            /// change the text using standard notifyDataSetChanged
            Button btn = (Button) findViewById(R.id.button);
            btn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mCurrData == 1) {
                        mCurrData = 3;
                        adapter.updateData(mData3);
                    } else {
                        mCurrData = 1;
                        adapter.updateData(mData1);
                    }
    
                    adapter.notifyDataSetChanged();
                }
    
            });
    
    
            /// change the text length between long <---> short  & invalidate()
            Button btn1 = (Button) findViewById(R.id.btn_invalidate);
            btn1.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mCurrData == 2) {
                        mCurrData = 1;
                        adapter.updateData(mData1);
                    } else {
                        mCurrData = 2;
                        adapter.updateData(mData2);
                    }
    
                    refreshVisibleListViewArea();
                    mListView.invalidate();
                }
            });
    
    
            /// change the text using row by row modification & invalidate()
            Button btn2 = (Button) findViewById(R.id.btn_invalidate2);
            btn2.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mCurrData == 3) {
                        mCurrData = 1;
                        adapter.updateData(mData1);
                    } else {
                        mCurrData = 3;
                        adapter.updateData(mData3);
                    }
                    refreshVisibleListViewArea();
                    mListView.invalidate();
                }
            });
    
    
            /// do nothing but invalidate()
            Button btn3 = (Button) findViewById(R.id.btn_invalidate3);
            btn3.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    refreshVisibleListViewArea();
                    mListView.invalidate();
                }
            });
        }
    
        private ArrayList<String> genRandomData(int offset) {
            ArrayList<String> tmp = new ArrayList<String>();
    
            for (int i = 0; i < N_ROW * 4; ++ i) {
                String a = "I_" + r.nextInt(N_ROW * 4 + offset);
                tmp.add(a);
            }
    
            return tmp;
        }
    
        private void refreshVisibleListViewArea() {
            int s = mListView.getFirstVisiblePosition();
            int e = mListView.getLastVisiblePosition();
            for (int i = s; i <= e; ++ i) {
                View v = mListView.getChildAt(i - s);
                mListView.getAdapter().getView(i, v, mListView);
            }
        }
    }
    

    适配器:

    public class ListViewAdapter extends ArrayAdapter<String> {
    
    
        private ArrayList<String> mData;
        private Context mContext;
    
        public ListViewAdapter(Context context, int resource, ArrayList<String> data) {
            super(context, resource, data);
            mContext = context;
            mData = data;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder vh = null;
            if (convertView == null) {
                LayoutInflater inflater = LayoutInflater.from(mContext);
                convertView = inflater.inflate(R.layout.list_item_name, parent, false);
                vh = new ViewHolder();
    
                vh.v1 = (TextView) convertView.findViewById(R.id.v1);
                vh.v2 = (TextView) convertView.findViewById(R.id.v2);
                vh.v3 = (TextView) convertView.findViewById(R.id.v3);
                vh.v4 = (TextView) convertView.findViewById(R.id.v4);
    
                convertView.setTag(vh);
            } else {
                vh = (ViewHolder) convertView.getTag();
            }
    
            if (vh.v1.getText() != mData.get(position * 4)) {
                vh.v1.setText(mData.get(position * 4));
            }
            if (vh.v2.getText() != mData.get(position * 4 + 1)) {
                vh.v2.setText(mData.get(position * 4 + 1));
            }
            if (vh.v3.getText() != mData.get(position * 4 + 2)) {
                vh.v3.setText(mData.get(position * 4 + 2));
            }
            if (vh.v4.getText() != mData.get(position * 4 + 3)) {
                vh.v4.setText(mData.get(position * 4 + 3));
            }
            return convertView;
        }
    
        public int getCount() {
            return MainActivity.N_ROW;
        }
    
        public void updateData(ArrayList<String> data) {
            mData = data;
        }
    
        class ViewHolder {
            TextView v1;
            TextView v2;
            TextView v3;
            TextView v4;
        }
    
    }
    

    list_item xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" >
    
        <TextView
            android:id="@+id/v1"
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="#f00"
            android:ellipsize="none"
            android:textSize="16sp" />
    
        <TextView
            android:id="@+id/v2"
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="#0f0"
            android:textSize="16sp" />
    
        <TextView
            android:id="@+id/v3"
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="#00f"
            android:ellipsize="none"
            android:textSize="16sp" />
    
        <TextView
            android:id="@+id/v4"
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="#0ff"
            android:ellipsize="none"
            android:textSize="16sp" />
    
    
    </LinearLayout>
    

1 个答案:

答案 0 :(得分:0)

经过一些分析工作,我相信我上面描述的情况,有太多的TextViews同时更新,因此很多资源被opengl绘制占用。

决定将udpate拆分成较小的。

最后,我使用表面视图来实现动画效果。 ;)