ListView添加Item动画以及四种冲突情况的解决办法

来源:互联网 发布:局域网 封端口 编辑:程序博客网 时间:2024/06/08 16:30

1. 动画功能的基本实现

首先我们梳理一下需求

  1. 界面上有三个元素,一个开启动画按钮start,一个关闭动画按钮end,一个ListView展示数据
  2. ListView默认是GONE的
  3. 点击开启动画按钮前,需要先将ListView置为VISIBLE,然后再开启动画。开启之后默认展示第一项。
  4. 点击关闭动画按钮后,在动画执行结束后,将ListView置为GONE。
  5. 点击ListView的Item后,也执行第4步骤的关闭动画操作。

我们知道,ViewGroup的动画需要LayoutAnimationController来支持,那么ListView继承于ViewGroup,当然也是通过LayoutAnimationController来实现Item的动画。这里需要注意的是,怎么拿到ListView最后一项Item的动画结束后的监听回调呢?代码如下:

/** * Created by chenchen on 2016/11/25. */public class ListViewAnimationListener implements Animation.AnimationListener {    private int count = 0;    private ListView listView;    private OnAnimationFinishListener listener;    public ListViewAnimationListener(ListView listView, OnAnimationFinishListener listener) {        this.listView = listView;        this.listener = listener;    }    @Override    public void onAnimationStart(Animation animation) {    }    @Override    public void onAnimationEnd(Animation animation) {        // 没有子控件,则直接完成        if(listView.getChildCount() == 0){            if(listener != null){                listener.onFinish();            }        }else{            count++;            if(count == listView.getChildCount() && listener != null){                listener.onFinish();                reset();            }        }    }    @Override    public void onAnimationRepeat(Animation animation) {    }    public void reset(){        count = 0;    }    public interface OnAnimationFinishListener{        void onFinish();    }}

代码很少,可以看出具体的逻辑是:每次动画结束时使变量count自增,当count等于listView的getChildCount()时,我们认为所有的Item的动画结束了。至于为什么是getChildCount()而不是adapter的getCount()呢?我们知道ListView的缓存原理,内存中始终只有屏幕可见个Item,因此动画是实际作用于真实存在内存中的Item。

好了,接下来贴出全部代码,其他部分就很简单了。

首先是两个动画文件:

<!-- translate_in --><?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android">    <translate xmlns:android="http://schemas.android.com/apk/res/android"        android:fromXDelta="-100%p" android:toXDelta="0%p"        android:duration="100"/></set><!-- translate_out --><?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android">    <translate xmlns:android="http://schemas.android.com/apk/res/android"        android:fromXDelta="0%p" android:toXDelta="-100%p"        android:duration="100" /></set>

然后是ListView的item文件,很简单

<?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="wrap_content"    android:gravity="center_vertical"    android:orientation="horizontal">    <ImageView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:src="@mipmap/ic_launcher" />    <TextView        android:id="@+id/txt"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:gravity="center"        android:textColor="@android:color/black"        android:textSize="15sp" /></LinearLayout>

然后是activity_main.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="vertical">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="60dp"        android:orientation="horizontal"        android:paddingLeft="20dp"        android:paddingRight="20dp"        >        <Button            android:id="@+id/start"            android:layout_width="0dp"            android:layout_weight="1"            android:layout_height="match_parent"            android:gravity="center"            android:text="开启列表动画"            android:textSize="18sp"            android:textColor="#333333"            />        <Button            android:id="@+id/end"            android:layout_width="0dp"            android:layout_weight="1"            android:layout_height="match_parent"            android:layout_marginLeft="20dp"            android:gravity="center"            android:text="关闭列表动画"            android:textSize="18sp"            android:textColor="#333333"            />    </LinearLayout>    <ListView        android:id="@+id/listView"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:cacheColorHint="@android:color/transparent"        android:listSelector="@android:color/transparent"        android:divider="#f1f1f1"        android:dividerHeight="1px"        android:visibility="gone"        /></LinearLayout>

最后是MainActivity文件

public class MainActivity extends Activity {    private ListView listView;    private MyAdapter adapter;    //动画控制器,针对ViewGroup的动画    private LayoutAnimationController inAnimationController;    private LayoutAnimationController outAnimationController;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initListView();        initBaseUI();    }    private void initBaseUI() {        findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                oepnAnim();            }        });        findViewById(R.id.end).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                closeAnim();            }        });    }    private void initListView() {        listView = (ListView) findViewById(R.id.listView);        adapter = new MyAdapter();        listView.setAdapter(adapter);        //设置点击监听器        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                closeAnim();            }        });        //入场动画        Animation inAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_in);        inAnimation.setFillAfter(true);        inAnimationController = new LayoutAnimationController(inAnimation);        inAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);        inAnimationController.setDelay(0.2f);        //设置动画结束监听器        ListViewAnimationListener inAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() {            @Override            public void onFinish() {            }        });        inAnimation.setAnimationListener(inAnimationListener);        //出场动画        Animation outAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_out);        outAnimation.setFillAfter(true);        outAnimationController = new LayoutAnimationController(outAnimation);        outAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);        outAnimationController.setDelay(0.2f);        //设置动画结束监听器        ListViewAnimationListener outAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() {            @Override            public void onFinish() {                listView.setVisibility(View.GONE);            }        });        outAnimation.setAnimationListener(outAnimationListener);    }    public class MyAdapter extends BaseAdapter{        @Override        public int getCount() {            return 30;        }        @Override        public Object getItem(int position) {            return null;        }        @Override        public long getItemId(int position) {            return position;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            ViewHolder holder = null;            if(convertView == null){                convertView = View.inflate(MainActivity.this, R.layout.item, null);                holder = new ViewHolder(convertView);                convertView.setTag(holder);            }else{                holder = (ViewHolder) convertView.getTag();            }            holder.fillData(position);            return convertView;        }        public class ViewHolder{            private TextView txt;            public ViewHolder(View rootView) {                txt = (TextView) rootView.findViewById(R.id.txt);            }            public void fillData(int position){                txt.setText("测试" + position);            }        }    }    private void oepnAnim(){        if(listView.getVisibility() == View.GONE){            //每次打开都在第一行            listView.setSelection(0);            listView.setVisibility(View.VISIBLE);            listView.setLayoutAnimation(inAnimationController);            listView.startLayoutAnimation();        }    }    private void closeAnim(){        if(listView.getVisibility() == View.VISIBLE){            listView.setLayoutAnimation(outAnimationController);            listView.startLayoutAnimation();        }    }}

2. 解决动画之间的冲突

做了以上部分,你就以为能够交差了?No,还差的很远。不信?连续点两次开启动画试试?是不是觉得这样的代码提交上去会被喷?

我列举了以下需要优化的地方:

  1. 连续快速点击两次开启动画按钮
  2. 连续快速点击两次关闭动画按钮
  3. 连续快速点击两次ListView的item
  4. 快速先点击开启动画按钮,再点击关闭动画按钮
  5. 快速先点击关闭动画按钮,再点击开启动画按钮
  6. 快速先点击开启动画按钮,再点击ListView的item
  7. 快速先点击ListView的item,再点击开启动画按钮
  8. 快速先点击关闭动画按钮,再点击ListView的item
  9. 快速先点击ListView的item,再点击开启动画按钮

看到上述9种情况,是不是瞬间觉得蛋疼无比?其实我们可以总结出一条规律:

再开启动画的过程中,不允许再开启第二个动画,否则视觉上会很奇怪

那么如何解决这个问题呢?很简单,只需要给出两个布尔变量canOpenAnim和canCloseAnim,表示是否允许开启open动画和close动画,在开启动画时,首先判断canOpenAnim或canCloseAnim的值,然后将canOpenAnim和canCloseAnim都置为false,在动画的完成监听器中再将canOpenAnim和canCloseAnim都置为true。这样就可以避免两个动画同时开启的尴尬。下面给出具体的代码:

public class MainActivity extends Activity {    private ListView listView;    private MyAdapter adapter;    //动画控制器,针对ViewGroup的动画    private LayoutAnimationController inAnimationController;    private LayoutAnimationController outAnimationController;    //控制解决连续多次动画的冲突    private boolean canOpenAnim = true;    private boolean canCloseAnim = true;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initListView();        initBaseUI();    }    private void initBaseUI() {        findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                openAnim();            }        });        findViewById(R.id.end).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                closeAnim();            }        });    }    private void initListView() {        listView = (ListView) findViewById(R.id.listView);        adapter = new MyAdapter();        listView.setAdapter(adapter);        //设置点击监听器        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                closeAnim();            }        });        //入场动画        Animation inAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_in);        inAnimation.setFillAfter(true);        inAnimationController = new LayoutAnimationController(inAnimation);        inAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);        inAnimationController.setDelay(0.2f);        //设置动画结束监听器        ListViewAnimationListener inAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() {            @Override            public void onFinish() {                canOpenAnim = true;                canCloseAnim = true;            }        });        inAnimation.setAnimationListener(inAnimationListener);        //出场动画        Animation outAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_out);        outAnimation.setFillAfter(true);        outAnimationController = new LayoutAnimationController(outAnimation);        outAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);        outAnimationController.setDelay(0.2f);        //设置动画结束监听器        ListViewAnimationListener outAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() {            @Override            public void onFinish() {                canOpenAnim = true;                canCloseAnim = true;                listView.setVisibility(View.GONE);            }        });        outAnimation.setAnimationListener(outAnimationListener);    }    public class MyAdapter extends BaseAdapter{        @Override        public int getCount() {            return 30;        }        @Override        public Object getItem(int position) {            return null;        }        @Override        public long getItemId(int position) {            return position;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            ViewHolder holder = null;            if(convertView == null){                convertView = View.inflate(MainActivity.this, R.layout.item, null);                holder = new ViewHolder(convertView);                convertView.setTag(holder);            }else{                holder = (ViewHolder) convertView.getTag();            }            holder.fillData(position);            return convertView;        }        public class ViewHolder{            private TextView txt;            public ViewHolder(View rootView) {                txt = (TextView) rootView.findViewById(R.id.txt);            }            public void fillData(int position){                txt.setText("测试" + position);            }        }    }    private void openAnim(){        if(canOpenAnim && listView.getVisibility() == View.GONE){            //要将两个标记都置为false,在动画的结束监听器中置为true            canOpenAnim = false;            canCloseAnim = false;            //每次打开都在第一行            listView.setSelection(0);            listView.setVisibility(View.VISIBLE);            listView.setLayoutAnimation(inAnimationController);            listView.startLayoutAnimation();        }    }    private void closeAnim(){        if(canCloseAnim && listView.getVisibility() == View.VISIBLE){            //要将两个标记都置为false,在动画的结束监听器中置为true            canOpenAnim = false;            canCloseAnim = false;            listView.setLayoutAnimation(outAnimationController);            listView.startLayoutAnimation();        }    }}

3. 动画与滑动时的冲突解决

当你弄完上面的代码之后,难道你以为就这么结束了?我还是要笑你太天真了。现在这样做:在点击开启动画的一瞬间,马上滑动ListView,此时是不是看见了很多Item是空白的?这是为什么呢?

我们知道ListView是有View的缓存的,在滚动的时候会自动将缓存的View进行再利用。此时开启动画是针对ListView内存中真实存在的View,也就是说在动画的时候再滑动,动画会与ListView的缓存策略相互冲突。主要有以下几种情况:

  1. 点击开启动画按钮时,马上滑动ListView
  2. 点击关闭动画按钮时,马上滑动ListView
  3. 点击ListView的item时,再马上滑动ListView
  4. 滑动ListView时,点击开启动画按钮
  5. 滑动ListView时,点击关闭动画按钮
  6. 滑动ListView时,再点击ListView的item

看见这么大一堆情况,是不是瞬间又懵逼了?不用怕,其实可以总结如下:

动画时要禁止ListView的滑动,滑动时要禁止ListView的动画

  • 禁止ListView的滑动可以通过设置ListView的setEnable(false),在开启动画时setEnabled(false),在动画完毕时设置setEnabled(true)
  • 滑动时禁止动画需要在OnScrollListener监听器回调中处理,当scrollState为SCROLL_STATE_IDLE时canOpenAnim和canCloseAnim设置为true,其他状态设置为false。
public class MainActivity extends Activity {    private ListView listView;    private MyAdapter adapter;    //动画控制器,针对ViewGroup的动画    private LayoutAnimationController inAnimationController;    private LayoutAnimationController outAnimationController;    //控制解决连续多次动画的冲突    private boolean canOpenAnim = true;    private boolean canCloseAnim = true;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initListView();        initBaseUI();    }    private void initBaseUI() {        findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                openAnim();            }        });        findViewById(R.id.end).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                closeAnim();            }        });    }    private void initListView() {        listView = (ListView) findViewById(R.id.listView);        adapter = new MyAdapter();        listView.setAdapter(adapter);        //设置点击监听器        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                closeAnim();        }        });        listView.setOnScrollListener(new AbsListView.OnScrollListener() {            @Override            public void onScrollStateChanged(AbsListView view, int scrollState) {                if(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE){                    //停止状态,允许开启关闭动画                    canOpenAnim = true;                    canCloseAnim = true;                }else{                    canOpenAnim = false;                    canCloseAnim = false;                }            }            @Override            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {            }        });        //入场动画        Animation inAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_in);        inAnimation.setFillAfter(true);        inAnimationController = new LayoutAnimationController(inAnimation);        inAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);        inAnimationController.setDelay(0.2f);        //设置动画结束监听器        ListViewAnimationListener inAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() {            @Override            public void onFinish() {                canOpenAnim = true;                canCloseAnim = true;                //恢复ListView的enabled属性                listView.setEnabled(true);            }        });        inAnimation.setAnimationListener(inAnimationListener);        //出场动画        Animation outAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_out);        outAnimation.setFillAfter(true);        outAnimationController = new LayoutAnimationController(outAnimation);        outAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);        outAnimationController.setDelay(0.2f);        //设置动画结束监听器        ListViewAnimationListener outAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() {            @Override            public void onFinish() {                canOpenAnim = true;                canCloseAnim = true;                //恢复ListView的enabled属性                listView.setEnabled(true);                listView.setVisibility(View.GONE);            }        });        outAnimation.setAnimationListener(outAnimationListener);    }    public class MyAdapter extends BaseAdapter{        @Override        public int getCount() {            return 30;        }        @Override        public Object getItem(int position) {            return null;        }        @Override        public long getItemId(int position) {            return position;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            ViewHolder holder = null;            if(convertView == null){                convertView = View.inflate(MainActivity.this, R.layout.item, null);                holder = new ViewHolder(convertView);                convertView.setTag(holder);            }else{                holder = (ViewHolder) convertView.getTag();            }            holder.fillData(position);            return convertView;        }        public class ViewHolder{            private TextView txt;            public ViewHolder(View rootView) {                txt = (TextView) rootView.findViewById(R.id.txt);            }            public void fillData(int position){                txt.setText("测试" + position);            }        }    }    private void openAnim(){        if(canOpenAnim && listView.getVisibility() == View.GONE){            //要将两个标记都置为false,在动画的结束监听器中置为true            canOpenAnim = false;            canCloseAnim = false;            //每次打开都在第一行            listView.setSelection(0);            listView.setVisibility(View.VISIBLE);            //设置ListView的enabled属性使不可滑动            listView.setEnabled(false);            listView.setLayoutAnimation(inAnimationController);            listView.startLayoutAnimation();        }    }    private void closeAnim(){        if(canCloseAnim && listView.getVisibility() == View.VISIBLE){            //要将两个标记都置为false,在动画的结束监听器中置为true            canOpenAnim = false;            canCloseAnim = false;            //设置ListView的enabled属性使不可滑动            listView.setEnabled(false);            listView.setLayoutAnimation(outAnimationController);            listView.startLayoutAnimation();        }    }}

4. 动画与ListView的缓存机制的冲突

当你完成了第3步,你是不是心里觉得这样总该差不多了吧?我只能告诉你快成功了,还有一个很关键的地方没有处理到。你也许想说,连滚动时的ListView的缓存机制都处理了,还能有什么情况?其实,滑动冲突只是缓存机制的一种情况,还有另外一种情况。这种情况出现在我项目中很长时间,一直没有找到对应的原因和解决办法。在一次偶然的机会我找到了原因,不看你肯定会后悔。

现在你这样做:首先点击开启动画按钮,将ListView展现出来,此时我的设备上展示了“测试0”到“测试23”一共24个Item,其中“测试23”只显示了部分。关键:现在往上滑动一点,让屏幕显示出“测试0”到“测试24”一共25个Item,其中“测试0”和“测试24”都是只显示了部分。你只需要保证滑动后的Item数会多一个就行。此时你点击关闭动画按钮,再点击开启动画按钮,往上滑动一点点,是不是发现了“测试24”这一项是一个空白呢?

为什么会这样呢?相信有的小伙伴儿已经心里有了答案。在关闭动画时,ListView有24项,在开启动画时,由于此时调用了setSession(0)方法,此时ListView只有23项,所以此时动画只针对这23项进行动画,而对第24项因为内部机制问题导致没有draw。

怎么解决呢?其实也是非常简单,在关闭动画开启前,手动再调用一次setSession(0),保证关闭动画和开启动画时,ListView的Item数是相同的就行

因为改动比较小,只添加了一行代码,因此就只粘贴这一段方法就行了:

private void closeAnim(){    if(canCloseAnim && listView.getVisibility() == View.VISIBLE){        //要将两个标记都置为false,在动画的结束监听器中置为true        canOpenAnim = false;        canCloseAnim = false;        //关闭动画时,保证此时的Item数与开启动画时相等,否则会产生最后一项不绘制的问题        listView.setSelection(0);        //设置ListView的enabled属性使不可滑动        listView.setEnabled(false);        listView.setLayoutAnimation(outAnimationController);        listView.startLayoutAnimation();    }}

5. 点击耗时任务处理时与滑动的冲突

本来完成了第4步,的确算大功告成了,但是在一次偶然的机会,我又玩出了一种冲突情况,这种情况就非常复杂了。

当我点击了Item响应OnItemClick后,先调用setEnabled(false),然后开启关闭动画,然后在动画监听器回调中,在调用了setEnabled(true)时,此时如果我再滑动ListView,由于enabled为true,visibility为VISIBLE,因此是可以滑动的,但是因为会马上执行动画监听器回调的后续代码,也就是调用setVisibility(View.GONE),因此此时的滑动效果是看不见的,但是的确是在滑动。此时如果滑动刚好导致Item数多了一个,那么下次再开启打开动画时,会导致最后一项无法绘制的问题,原因第4步已经讲了

也就是说,如果onItemClick比较耗时,此时点击一个item时,立刻使劲儿滑动ListView,会有一定几率导致下一次打开ListView时有一项无法绘制是空白项。

怎么解决呢?其实也很简单。一切都是在关闭动画监听器中设置了setEnabled(true)导致的,那么可以将这行代码注释掉,因为在开启动画监听器一定会调用setEnabled(true)。屏蔽掉在关闭动画后还有一定几率对ListView进行操作的情况。

//设置动画结束监听器ListViewAnimationListener outAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() {    @Override    public void onFinish() {        canOpenAnim = true;        canCloseAnim = true;        //关闭动画后不释放enabled,在开启动画后释放,否则会在点击后使劲儿滑动ListView,        //会有一定几率造成ListView滑动,造成Item数多一个,导致ListView最后一项无法绘制//      listView.setEnabled(true);        listView.setVisibility(View.GONE);    }});

6. 解决所有冲突的完整的Activity代码

public class MainActivity extends Activity {    private ListView listView;    private MyAdapter adapter;    //动画控制器,针对ViewGroup的动画    private LayoutAnimationController inAnimationController;    private LayoutAnimationController outAnimationController;    //控制解决连续多次动画的冲突    private boolean canOpenAnim = true;    private boolean canCloseAnim = true;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initListView();        initBaseUI();    }    private void initBaseUI() {        findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                openAnim();            }        });        findViewById(R.id.end).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                closeAnim();            }        });    }    private void initListView() {        listView = (ListView) findViewById(R.id.listView);        adapter = new MyAdapter();        listView.setAdapter(adapter);        //设置点击监听器        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                closeAnim();        }        });        listView.setOnScrollListener(new AbsListView.OnScrollListener() {            @Override            public void onScrollStateChanged(AbsListView view, int scrollState) {                if(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE){                    //停止状态,允许开启关闭动画                    canOpenAnim = true;                    canCloseAnim = true;                }else{                    canOpenAnim = false;                    canCloseAnim = false;                }            }            @Override            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {            }        });        //入场动画        Animation inAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_in);        inAnimation.setFillAfter(true);        inAnimationController = new LayoutAnimationController(inAnimation);        inAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);        inAnimationController.setDelay(0.2f);        //设置动画结束监听器        ListViewAnimationListener inAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() {            @Override            public void onFinish() {                canOpenAnim = true;                canCloseAnim = true;                //恢复ListView的enabled属性                listView.setEnabled(true);            }        });        inAnimation.setAnimationListener(inAnimationListener);        //出场动画        Animation outAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_out);        outAnimation.setFillAfter(true);        outAnimationController = new LayoutAnimationController(outAnimation);        outAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);        outAnimationController.setDelay(0.2f);        //设置动画结束监听器        ListViewAnimationListener outAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() {            @Override            public void onFinish() {                canOpenAnim = true;                canCloseAnim = true;                //关闭动画后不释放enabled,在开启动画后释放,否则会在点击后使劲儿滑动ListView,                //会有一定几率造成ListView滑动,造成Item数多一个,导致ListView最后一项无法绘制//                listView.setEnabled(true);                listView.setVisibility(View.GONE);            }        });        outAnimation.setAnimationListener(outAnimationListener);    }    public class MyAdapter extends BaseAdapter{        @Override        public int getCount() {            return 30;        }        @Override        public Object getItem(int position) {            return null;        }        @Override        public long getItemId(int position) {            return position;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            ViewHolder holder = null;            if(convertView == null){                convertView = View.inflate(MainActivity.this, R.layout.item, null);                holder = new ViewHolder(convertView);                convertView.setTag(holder);            }else{                holder = (ViewHolder) convertView.getTag();            }            holder.fillData(position);            return convertView;        }        public class ViewHolder{            private TextView txt;            public ViewHolder(View rootView) {                txt = (TextView) rootView.findViewById(R.id.txt);            }            public void fillData(int position){                txt.setText("测试" + position);            }        }    }    private void openAnim(){        if(canOpenAnim && listView.getVisibility() == View.GONE){            //要将两个标记都置为false,在动画的结束监听器中置为true            canOpenAnim = false;            canCloseAnim = false;            //每次打开都在第一行            listView.setSelection(0);            listView.setVisibility(View.VISIBLE);            //设置ListView的enabled属性使不可滑动            listView.setEnabled(false);            listView.setLayoutAnimation(inAnimationController);            listView.startLayoutAnimation();        }    }    private void closeAnim(){        if(canCloseAnim && listView.getVisibility() == View.VISIBLE){            //要将两个标记都置为false,在动画的结束监听器中置为true            canOpenAnim = false;            canCloseAnim = false;            //关闭动画时,保证此时的Item数与开启动画时相等,否则会产生最后一项不绘制的问题            listView.setSelection(0);            //设置ListView的enabled属性使不可滑动            listView.setEnabled(false);            listView.setLayoutAnimation(outAnimationController);            listView.startLayoutAnimation();        }    }}
阅读全文
1 0
原创粉丝点击