android listview item点击展开
最近做项目真是头疼呢?之前想用ListViewAnnotation来着,就是可以实现类似于android 通知栏滑动删除的效果。好像是一位大牛自己一个人写的吧。我在这里首先向他致敬。不过,话说回来,实现原理也是比较易于理解的,就是检测你的滑动距离以及速度,再作出判断,进行操作。具体大家参考下Google keep的两种列表模式下滑动删除的操作就理解类。
非常不幸的事,我再布局中用了fragment和biewpager,所以产生了手势冲突,我为此改写了library里的手势操作检测方法,最后勉强改出来的。但是!!!!效果实在惨不忍睹,只好作罢,最后,思来想去,我决定使用listview item点击展开来实现我想要的效果。
好吧,废话说了很多,终于要进入正题了。
首先补充三点知识:
第一点:
getLayoutParams()方法和setLayoutParams()用法
首先,我们利用getLayoutParams()来获得指定控件的LayoutParams。例如:
LinearLayout.LayoutParams lp = (RelativeLayout.LayoutParams) deletButton.getLayoutParams();
然后,我们可以为deleteButton设置layoutparams属性,例如:
lp.width = btnWidth;
lp.leftMargin = 10;
最后,我们将设置好的layoutparams属性设置给指定的控件: deletButton.setLayoutParams(lp);
第二点:
public final int getMeasuredHeight ()
Added in API level 1
Like getMeasuredHeightAndState(), but only returns the raw width component (that is the result is masked by MEASURED_SIZE_MASK).
Returns
The raw measured height of this view.
public final int getHeight ()
Added in API level 1
Return the height of your view.
Returns
The height of your view, in pixels.
getMeasuredHeight()返回的是原始测量高度,与屏幕无关,getHeight()返回的是在屏幕上显示的高度。实际上在当屏幕可以包裹内容的时候,他们的值是相等的,只有当view超出屏幕后,才能看出他们的区别。当超出屏幕后,getMeasuredHeight()等于getHeight()加上屏幕之外没有显示的高度。
第三点:
MeasureSpec的使用。MeasureSpec一般出现在自定义View中,因为在自定义 view中我们经常需要重写该方法,由它来指定自定义控件在屏幕上的大小。
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
onMeasure传入的两个参数是由上一层控件传入的大小,有多种情况,重写该方法时需要对计算控件的实际大小,然后调用setMeasuredDimension(int, int)设置实际大小。
onMeasure传入的widthMeasureSpec和heightMeasureSpec不是一般的尺寸数值,而是将模式和尺寸组合在一起的数值。我们需要通过int mode = MeasureSpec.getMode(widthMeasureSpec)得到模式,用int size = MeasureSpec.getSize(widthMeasureSpec)得到尺寸。
mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, MeasureSpec.AT_MOST。
MeasureSpec.EXACTLY是精确尺寸,当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。
MeasureSpec.AT_MOST是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。
然后,我们可以调用MeasureSpec.makeMeasureSpec(int size, int mode)来进行设置。
好,现在先上一张demo截图,使用者可以自己进行扩充。
哈哈,效果还行吧。那个,图标略显呆萌,还请不要见笑(自己绘制的,苦逼程序员一只啊)。
好,接下来,我们来看一下动效的实现。当然,先上源码。
package wenyue.expandlistview.me;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.LinearLayout.LayoutParams;
/**
* animation
* 2014年十一月十八日
* 苍狼问月
* canglangwenyue.github.io
* @author canglangwenyue
*
*/
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);
}
@Override
protected 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);
}
}
Log.i("hehe", "interpolatedTime = " + interpolatedTime + " , bottomMargin" +
mViewLayoutParams.bottomMargin);
}
}
动效实现的代码不多,setDuration(duration)设置动效的持续时间。之后调用RelitaveLayout.bottomMargin;对于该属性developer文档解释为The bottom margin in pixels of the child.
mAnimationView.requestLayout();该方法内部会调用Object.layout(...)方法,来重会布局。
至于,listview adapter的重写,就比较简单了。所以,不再贴出全部源码。只说一下需要注意的地方。
首先,你需要在getView(…)中加载自定义listview 的item布局文件:
convertView = myInflater.inflate(R.layout.expand_item, null);
接下来,贴出相应布局文件代码:
<?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:orientation="vertical"
android:padding="5dip" >
<RelativeLayout
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:id="@+id/appInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:orientation="vertical" >
<TextView
android:id="@+id/tvName"
android:layout_width="match_parent"
android:layout_height="45dp"
android:gravity="center|left"
android:text="name"
android:textColor="#000000"
android:layout_marginLeft="20.0dip"
android:textSize="16sp" />
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff" >
<Button
android:id="@+id/btnOpen"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginTop="6dip"
android:focusable="false"
android:textColor="#000000"
android:background="@drawable/editbutton"
android:textSize="16sp" />
<Button
android:id="@+id/btnView"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_marginTop="6dip"
android:layout_toRightOf="@id/btnOpen"
android:focusable="false"
android:background="@drawable/start"
android:textColor="#000000"
android:textSize="16sp" />
<Button
android:id="@+id/btnWarning"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginTop="6dip"
android:focusable="false"
android:background="@drawable/tomatodeletebutton"
android:textColor="#000000"
android:textSize="16sp" />
</RelativeLayout>
</LinearLayout>
我设置的是默认在activity onStart时嵌套布局中的第二个RelativeLayout布局文件的内容是被隐藏的。
在BaseAdapter中的设置如下:
RelativeLayout footer = (RelativeLayout) convertView
.findViewById(R.id.footer);
int widthSpec = MeasureSpec.makeMeasureSpec(
(int) (mLcdWidth - 10 * mDensity), MeasureSpec.EXACTLY);
footer.measure(widthSpec, 0);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) footer
.getLayoutParams();
params.bottomMargin = -footer.getMeasuredHeight();
footer.setVisibility(View.GONE);
然后,是在onCreate方法中设置setOnItemClickListener方法,在其中设置点击item后,开始动效,再次点击则隐藏,且同一时间只有一个item可以展开(因为个人认为用户不可能在同一时间操作两个 item的隐藏操作),代码如下:
if (mLastTouchTag != null) {
View temp = arg0.findViewWithTag(mLastTouchTag);
if (temp != null) {
View footTemp = temp.findViewById(R.id.footer);
if (footTemp != null
&& (footTemp.getVisibility() != View.GONE)) {
footTemp.startAnimation(new ViewExpandAnimation(
footTemp));
}
}
}
mLastTouchTag = (ViewHolder) v.getTag();
// onion555 end
View footer = v.findViewById(R.id.footer);
footer.startAnimation(new ViewExpandAnimation(footer));
好吧,就写到这里吧,有什么问题,请留言。同样,在最后附上源码下载地址。
点击打开链接
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。