仿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(加入了子列表渐入渐出的动画)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux 进程监控命令2——ps
- 下一篇: 指令 机器指令 汇编指令 指令系统