您的位置:首页 > 其它

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

2017-07-10 16:48 483 查看

1. 动画功能的基本实现

首先我们梳理一下需求

界面上有三个元素,一个开启动画按钮start,一个关闭动画按钮end,一个ListView展示数据

ListView默认是GONE的

点击开启动画按钮前,需要先将ListView置为VISIBLE,然后再开启动画。开启之后默认展示第一项。

点击关闭动画按钮后,在动画执行结束后,将ListView置为GONE。

点击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,还差的很远。不信?连续点两次开启动画试试?是不是觉得这样的代码提交上去会被喷?

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

连续快速点击两次开启动画按钮

连续快速点击两次关闭动画按钮

连续快速点击两次ListView的item

快速先点击开启动画按钮,再点击关闭动画按钮

快速先点击关闭动画按钮,再点击开启动画按钮

快速先点击开启动画按钮,再点击ListView的item

快速先点击ListView的item,再点击开启动画按钮

快速先点击关闭动画按钮,再点击ListView的item

快速先点击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的缓存策略相互冲突。主要有以下几种情况:

点击开启动画按钮时,马上滑动ListView

点击关闭动画按钮时,马上滑动ListView

点击ListView的item时,再马上滑动ListView

滑动ListView时,点击开启动画按钮

滑动ListView时,点击关闭动画按钮

滑动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(); } }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐