仿Expandablelistview效果的ListView(加入了子列表渐入渐出的动画)
新来的项目要求第一眼一看就是用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(加入了子列表渐入渐出的动画)相关推荐
- 微信小程序-实现元素渐入渐出动画效果-封装方法
开端 之前一直使用堪称"万能"的jQuery处理用户交互的动画,近日开发微信小程序,微信小程序高度限制的语法和功能使开源函数可谓对其"无能为力". 那没办法,只 ...
- MASM32编程实现窗口渐入渐出效果
因为工作太忙,好久没写程序代码了,不过编写程序的乐趣令我乐此不疲. 天天跟电脑打交道,一忙起来就忘了休息,弄得眼睛都花了~ 为了保护眼睛,偶决定写一个定时强制休息的程序~ 虽然现在这类程序已有不少,不 ...
- html5页面滑入滑出效果,jQuery实现的淡入淡出与滑入滑出效果示例
本文实例讲述了jQuery实现的淡入淡出与滑入滑出效果.分享给大家供大家参考,具体如下: 1. 淡入淡出效果: 我们做这样一个实例: 有两个按钮,点击淡入,有一个div层淡入,点击淡出,div层淡出: ...
- [Unity3D]Unity3D游戏开发之Logo渐入渐出效果的实现
---------------------------------------------------------------------------------------------------- ...
- vue中怎样实现弹出层动画效果?由上而下渐渐显示---封装成复用组件
子组件: <template><div class="home"><!-- 首先将要过渡的元素用transition包裹,并设置过渡的name --& ...
- python能制作ppt动画效果吗_原来用PPT也能做出神级的动画效果!
一个好的PPT不光需要整齐的格式.精彩的文案和配图,有时一个动画也能产生非常棒的吸睛效果,为整个PPT添加灵动的色彩. 但是大部分人会使用(或者说常使用)的动画就那么几种:百叶窗.飞入.飞出.弹跳-这 ...
- [Android精品源码] Android 仿美团网,探索ListView的A-Z字母排序功能实现选择城市
Material Design中文版Code4APPPHP100UI4APP 开启辅助访问设为首页收藏本站快捷导航切换到宽版切换风格 石刚 | |我的 |签到打卡 |设置 |消息 |提醒(2) |退出 ...
- android饿了么购物车,Android仿饿了么加入购物车旋转控件自带闪转腾挪动画的按钮效果(实例详解)...
概述 在上文,酷炫Path动画已经预告了,今天给大家带来的是利用 纯自定义View,实现的仿饿了么加入购物车控件,自带闪转腾挪动画的按钮. 效果图如下: 图1 项目中使用的效果,考虑到了View的回收 ...
- android 仿微信demo————微信顶部操作栏加号按钮实现(弹出子菜单)
android 仿微信demo----微信启动界面实现 android 仿微信demo----注册功能实现(移动端) android 仿微信demo----注册功能实现(服务端) android 仿微 ...
最新文章
- 鲲鹏服务器光盘安装操作系统,鲲鹏服务器上安装
- 同学报了计算机专业,大学各专业另类“炫富”,医学专业毫不意外,计算机专业没人羡慕...
- 章鱼哥出品—VB.NET DataGridView绑定数据源 quot;与货币管理器的位置关联的行不能设置为不可见quot; 问题的解决...
- 理解SQLNET.AUTHENTICATION_SERVICES参数|转|
- 数字语音信号处理学习笔记——语音信号的数字模型(3)
- 09_Fibonacci
- BD和DBMS和SQL概念
- [渝粤教育] 西南科技大学 英语语法1 在线考试复习资料
- MadFS:高性能超算缓存文件系统——助力“鹏城云脑II”获世界IO500排行榜冠军...
- mysql集群如何保障数据分布均匀_如何保证数据库集群时候,主从库一致性的问题?...
- 远程客户端连接linux,远程控制服务(SSH)之Linux环境下客户端与服务端的远程连接...
- python人像绘制_python实现人像动漫化的示例代码
- GPS NMEA0183协议解析(转载)
- Windows 2000 安全检查清单( 摘自《网络与安全》)
- 替换一个文件的字符串
- 修改Ceph 监视器地址
- Ubuntu18.04安装搜狗输入法不能 用的问题20211221
- 十年一梦,小米的原罪得到救赎了吗?
- 麻省理工学院计算机科学,麻省理工学院素以世界顶尖的工程学和计算机科学而享誉世界[1-2] ,位列2015-16年世...
- 一文读懂JVM虚拟机:JVM虚拟机的内存管理(万字详解)
热门文章
- NOCOUNT如何影响ADO.NET(SET NOCOUNT ON的性能问题)
- 当你真的去买菜的时候,你就知道为什么奶奶姥姥对于价格那么敏感,为什么喜欢打折?
- U3D 文档 GPU INSTANCING
- 【题解】 P4139 上帝与集合的正确用法
- 一步一步理解Java 企业级应用的可扩展性
- golang 程序部署及Supervisord deamon 运行
- ASP用DSN连接数sql数据库
- Log4net 中输出日志到文件,文件名根据日期生成
- hdu 5340(manacher+枚举)
- ZT Android4.2蓝牙基础架构学习