新来的项目要求第一眼一看就是用Expandablelistview。效果图如下:

           

  其实本来希望直接使用Expandablelistview的,但是需求Expandablelistview在展开一个group时有个动画效果——该group的child一个一个滑动出来并且把下面的group“挤”下去。本以为这个Expandablelistview组件肯定有相关方法的,但竟然没有!网上居然也查不到(有很多人问同样的问题,答案却都是:继承Expandablelistview然后自定义这个动画,然后没了。究竟怎样自定义动画啊有没有搞错!)只好找了下Expandablelistview的方法,有个expandGroup()方法:

    /*** Expand a group in the grouped list view** @param groupPos the group to be expanded* @return True if the group was expanded, false otherwise (if the group*         was already expanded, this will return false)*/public boolean expandGroup(int groupPos) {return expandGroup(groupPos, false);}

  看到它其实是执行了expandGroup(groupPos, false)方法,鼠标挪到方法上一看

  心中一阵狂喜,第二个参数不是是否使用动画么?!赶紧点进去看,结果……

    /*** Expand a group in the grouped list view** @param groupPos the group to be expanded* @param animate true if the expanding group should be animated in* @return True if the group was expanded, false otherwise (if the group*         was already expanded, this will return false)*/public boolean expandGroup(int groupPos, boolean animate) {ExpandableListPosition elGroupPos = ExpandableListPosition.obtain(ExpandableListPosition.GROUP, groupPos, -1, -1);PositionMetadata pm = mConnector.getFlattenedPos(elGroupPos);elGroupPos.recycle();boolean retValue = mConnector.expandGroup(pm);if (mOnGroupExpandListener != null) {mOnGroupExpandListener.onGroupExpand(groupPos);}if (animate) {final int groupFlatPos = pm.position.flatListPos;final int shiftedGroupPosition = groupFlatPos + getHeaderViewsCount();smoothScrollToPosition(shiftedGroupPosition + mAdapter.getChildrenCount(groupPos),shiftedGroupPosition);}pm.recycle();return retValue;}

  看到if(animate)语句瞬间无语了,只是执行了smoothScrollToPosition()就是加了动画效果?太坑了!无奈只好另辟蹊径来实现。

  (废话多了些,现在进入正题。)

  先在网上搜索看到一篇博文:http://blog.csdn.net/qingye_love/article/details/8858147。

  正是我想要的动画效果,写得很详细,不过他是弹出一个很短的操作界面(只有3个button),我想干脆用listView嵌套listView,然后把它的效果拿来用好了。

  主布局文件list_list_layout.xml,很简单,就一个ListView,这个ListView的每个子项对应Expandablelistview的一个Group项:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><ListView android:id="@+id/lv"android:layout_width="match_parent"android:layout_height="match_parent"android:focusable="false"></ListView></RelativeLayout>

  然后是每个ListView子项布局list_item_layout.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" ><RelativeLayout android:layout_width="match_parent"android:layout_height="wrap_content"><ImageView android:id="@+id/listview_item_icon"android:layout_width="48dp"android:layout_height="48dp"android:layout_margin="5dp"android:layout_centerVertical="true"/><TextView android:id="@+id/listview_item_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:singleLine="true"android:textColor="#000"android:textSize="20dp"android:layout_marginLeft="60dp"android:layout_alignBaseline="@id/listview_item_icon"/></RelativeLayout><RelativeLayout android:id="@+id/listview_item_footer"android:layout_width="match_parent"android:layout_height="wrap_content"android:descendantFocusability="blocksDescendants"android:focusable="false"><ListView android:id="@+id/listview_item_lv"android:layout_width="match_parent"android:layout_height="wrap_content"android:focusable="false"></ListView></RelativeLayout></LinearLayout>

  每个Group项由一个ImageView和一个TextView组成,然后下面有个RelativeLayout,id为listview_item_footer,这个RelativeLayout里有个listView,这个就是每个Group下的子列表了。

  对应每个子ListView,也就是没一个Group,适配器写法与普通无异:

import java.util.List;import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;public class ItemAdapter extends BaseAdapter{private List<SeletorDataInfo> devList;private LayoutInflater mInflater;public ItemAdapter(Context mContext, List<SeletorDataInfo> devList){this.devList = devList;mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);}@Overridepublic int getCount() {// TODO Auto-generated method stubif(null == devList)return 0;else {return devList.size();}}@Overridepublic SeletorDataInfo getItem(int position) {// TODO Auto-generated method stubif(null == devList)return null;else {return devList.get(position);}}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// TODO Auto-generated method stubItemHolder itemHolder = null;if (null == convertView) {itemHolder = new ItemHolder();convertView = mInflater.inflate(R.layout.item_item_layout, null);itemHolder.name = (TextView) convertView.findViewById(R.id.item_item_name);itemHolder.icon = (ImageView) convertView.findViewById(R.id.item_item_icon);convertView.setTag(itemHolder);} else {itemHolder = (ItemHolder) convertView.getTag();}SeletorDataInfo mSelfData = getItem(position);if (null != mSelfData) {itemHolder.name.setText(mSelfData.getName());itemHolder.icon.setBackground(mSelfData.getIcon());}return convertView;}private class ItemHolder {ImageView icon;TextView name;}}

  其中SeletorDataInfo是我自己定义的数据类。然后是所有Group的适配器:

import java.util.List;import android.content.Context;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;public class ListViewAdapter extends BaseAdapter{private Context mContext;private List<SeletorDataInfo> roomList;private List<List<SeletorDataInfo>> allList;private LayoutInflater mInflater;private int mLcdWidth = 0;  private float mDensity = 0; private final int itemWidth;public ListViewAdapter(Context mContext, List<SeletorDataInfo> roomList, List<List<SeletorDataInfo>> allList){this.mContext = mContext;this.roomList = roomList;this.allList = allList;mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);DisplayMetrics dm = mContext.getResources().getDisplayMetrics();  mLcdWidth = dm.widthPixels;  mDensity = dm.density; //这里我每个列表项高度是59dp。itemWidth = (int) (59 * mDensity);}@Overridepublic int getCount() {// TODO Auto-generated method stubif(null == roomList)return 0;else {return roomList.size();}}@Overridepublic SeletorDataInfo getItem(int position) {// TODO Auto-generated method stubif(null == roomList)return null;else {return roomList.get(position);}}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {// TODO Auto-generated method stubViewHolder viewHolder = null;if (null == convertView) {viewHolder = new ViewHolder();convertView = mInflater.inflate(R.layout.list_item_layout, null);viewHolder.name = (TextView) convertView.findViewById(R.id.listview_item_name);viewHolder.icon = (ImageView) convertView.findViewById(R.id.listview_item_icon);viewHolder.lv = (ListView) convertView.findViewById(R.id.listview_item_lv);convertView.setTag(viewHolder);} else {viewHolder = (ViewHolder) convertView.getTag();}SeletorDataInfo mSelfData = roomList.get(position);if (null != mSelfData) {viewHolder.name.setText(mSelfData.getName());viewHolder.icon.setBackground(mSelfData.getIcon());viewHolder.lv.setAdapter(new ItemAdapter(mContext, allList.get(position)));}//**********************************************************************************************************RelativeLayout footer = (RelativeLayout) convertView.findViewById(R.id.listview_item_footer); //不明白为什么宽度被设成:屏宽减去10dp(mLcdWidth - 10 * mDensity),不过不去深究这个,因为我们关心的是高度。int widthSpec = MeasureSpec.makeMeasureSpec((int) (mLcdWidth - 10 * mDensity), MeasureSpec.EXACTLY);//然后,调用measure()方法,宽度被设成上面的widthSpec,而高度传了个0,不过没有关系因为高度下面才会设置footer.measure(widthSpec, 0);  LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) footer.getLayoutParams();//在此设置高度为:该组(Group)的项目数 * 每一项的高度。//本来我参看的那篇博文用的是params.bottomMargin = -footer.getMeasuredHeight(); //但我使用时取footer.getMeasuredHeight(); 总出问题,第一次取只有listView一项的高度,后面高度也不匹配//不知道是listView缓存机制带来的问题还是什么,这里如果知道没一个列表项的高度,照现在的写法也没有问题。params.height = (allList.get(position).size() * itemWidth);if(roomList.get(position).state == 0) {params.bottomMargin = - params.height;footer.setVisibility(View.GONE);} else {params.bottomMargin = 0;footer.setVisibility(View.VISIBLE);}//**********************************************************************************************************return convertView;}private class ViewHolder {ImageView icon;TextView name;ListView lv;}}

  与之前的adapter不同的地方主要在星号之间的代码,原理其实很简单,先测出你子ListView(比如名为mListView)所占的高度(比如高度为mHeight),然后把这个mListView的LayoutParams.bottomMargin = -mHeight;这样,其实mListView正好在其父布局的外面(其父布局正是footer)。然后下面的动画类中,不断设置这个LayoutParams.bottomMargin的值,让它从-mHeight逐渐变为0。那么,这个mListView就好像从两个Group项中“挤出来”的感觉一样。

  然后是自定义动画:

import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.LinearLayout.LayoutParams;public class ViewExpandAnimation extends Animation {private View mAnimationView = null;private LayoutParams mViewLayoutParams = null;private int mStart = 0;private int mEnd = 0;public ViewExpandAnimation(View view){animationSettings(view, 500);}public ViewExpandAnimation(View view, int duration){animationSettings(view, duration);}private void animationSettings(View view, int duration){setDuration(duration);mAnimationView = view;mViewLayoutParams = (LayoutParams) view.getLayoutParams();mStart = mViewLayoutParams.bottomMargin;mEnd = (mStart == 0 ? (0 - view.getHeight()) : 0);view.setVisibility(View.VISIBLE);}@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {super.applyTransformation(interpolatedTime, t);if(interpolatedTime < 1.0f){mViewLayoutParams.bottomMargin = mStart + (int) ((mEnd - mStart) * interpolatedTime);// invalidate
            mAnimationView.requestLayout();}else{mViewLayoutParams.bottomMargin = mEnd;mAnimationView.requestLayout();if(mEnd != 0){mAnimationView.setVisibility(View.GONE);}}}
}

  activity中加入如下片段即可:

        mListViewAdapter = new ListViewAdapter(this, roomList, allList);mListView.setAdapter(mListViewAdapter);mListView.setOnItemClickListener(new OnItemClickListener(){  @Override  public void onItemClick(AdapterView<?> arg0, View v, int pos,  long arg3) {  View footer = v.findViewById(R.id.listview_item_footer);  footer.startAnimation(new ViewExpandAnimation(footer));  if(roomList.get(pos).state == 0) {roomList.get(pos).state = 1;} else {roomList.get(pos).state = 0;}}  });

转载于:https://www.cnblogs.com/Couch-potato/p/3756716.html

仿Expandablelistview效果的ListView(加入了子列表渐入渐出的动画)相关推荐

  1. 微信小程序-实现元素渐入渐出动画效果-封装方法

    开端 之前一直使用堪称"万能"的jQuery处理用户交互的动画,近日开发微信小程序,微信小程序高度限制的语法和功能使开源函数可谓对其"无能为力". 那没办法,只 ...

  2. MASM32编程实现窗口渐入渐出效果

    因为工作太忙,好久没写程序代码了,不过编写程序的乐趣令我乐此不疲. 天天跟电脑打交道,一忙起来就忘了休息,弄得眼睛都花了~ 为了保护眼睛,偶决定写一个定时强制休息的程序~ 虽然现在这类程序已有不少,不 ...

  3. html5页面滑入滑出效果,jQuery实现的淡入淡出与滑入滑出效果示例

    本文实例讲述了jQuery实现的淡入淡出与滑入滑出效果.分享给大家供大家参考,具体如下: 1. 淡入淡出效果: 我们做这样一个实例: 有两个按钮,点击淡入,有一个div层淡入,点击淡出,div层淡出: ...

  4. [Unity3D]Unity3D游戏开发之Logo渐入渐出效果的实现

    ---------------------------------------------------------------------------------------------------- ...

  5. vue中怎样实现弹出层动画效果?由上而下渐渐显示---封装成复用组件

    子组件: <template><div class="home"><!-- 首先将要过渡的元素用transition包裹,并设置过渡的name --& ...

  6. python能制作ppt动画效果吗_原来用PPT也能做出神级的动画效果!

    一个好的PPT不光需要整齐的格式.精彩的文案和配图,有时一个动画也能产生非常棒的吸睛效果,为整个PPT添加灵动的色彩. 但是大部分人会使用(或者说常使用)的动画就那么几种:百叶窗.飞入.飞出.弹跳-这 ...

  7. [Android精品源码] Android 仿美团网,探索ListView的A-Z字母排序功能实现选择城市

    Material Design中文版Code4APPPHP100UI4APP 开启辅助访问设为首页收藏本站快捷导航切换到宽版切换风格 石刚 | |我的 |签到打卡 |设置 |消息 |提醒(2) |退出 ...

  8. android饿了么购物车,Android仿饿了么加入购物车旋转控件自带闪转腾挪动画的按钮效果(实例详解)...

    概述 在上文,酷炫Path动画已经预告了,今天给大家带来的是利用 纯自定义View,实现的仿饿了么加入购物车控件,自带闪转腾挪动画的按钮. 效果图如下: 图1 项目中使用的效果,考虑到了View的回收 ...

  9. android 仿微信demo————微信顶部操作栏加号按钮实现(弹出子菜单)

    android 仿微信demo----微信启动界面实现 android 仿微信demo----注册功能实现(移动端) android 仿微信demo----注册功能实现(服务端) android 仿微 ...

最新文章

  1. 鲲鹏服务器光盘安装操作系统,鲲鹏服务器上安装
  2. 同学报了计算机专业,大学各专业另类“炫富”,医学专业毫不意外,计算机专业没人羡慕...
  3. 章鱼哥出品—VB.NET DataGridView绑定数据源 quot;与货币管理器的位置关联的行不能设置为不可见quot; 问题的解决...
  4. 理解SQLNET.AUTHENTICATION_SERVICES参数|转|
  5. 数字语音信号处理学习笔记——语音信号的数字模型(3)
  6. 09_Fibonacci
  7. BD和DBMS和SQL概念
  8. [渝粤教育] 西南科技大学 英语语法1 在线考试复习资料
  9. MadFS:高性能超算缓存文件系统——助力“鹏城云脑II”获世界IO500排行榜冠军...
  10. mysql集群如何保障数据分布均匀_如何保证数据库集群时候,主从库一致性的问题?...
  11. 远程客户端连接linux,远程控制服务(SSH)之Linux环境下客户端与服务端的远程连接...
  12. python人像绘制_python实现人像动漫化的示例代码
  13. GPS NMEA0183协议解析(转载)
  14. Windows 2000 安全检查清单( 摘自《网络与安全》)
  15. 替换一个文件的字符串
  16. 修改Ceph 监视器地址
  17. Ubuntu18.04安装搜狗输入法不能 用的问题20211221
  18. 十年一梦,小米的原罪得到救赎了吗?
  19. 麻省理工学院计算机科学,麻省理工学院素以世界顶尖的工程学和计算机科学而享誉世界[1-2] ,位列2015-16年世...
  20. 一文读懂JVM虚拟机:JVM虚拟机的内存管理(万字详解)

热门文章

  1. NOCOUNT如何影响ADO.NET(SET NOCOUNT ON的性能问题)
  2. 当你真的去买菜的时候,你就知道为什么奶奶姥姥对于价格那么敏感,为什么喜欢打折?
  3. U3D 文档 GPU INSTANCING
  4. 【题解】 P4139 上帝与集合的正确用法
  5. 一步一步理解Java 企业级应用的可扩展性
  6. golang 程序部署及Supervisord deamon 运行
  7. ASP用DSN连接数sql数据库
  8. Log4net 中输出日志到文件,文件名根据日期生成
  9. hdu 5340(manacher+枚举)
  10. ZT Android4.2蓝牙基础架构学习