标签:
在接下来的几篇文章将任老师的博文《您可以下拉PinnedHeaderExpandableListView实现》骤来具体实现。来学习一下大神的代码并记录一下。
原文出处:http://blog.csdn.net/singwhatiwanna/article/details/25546871
先看一下终于效果:
新建一个activity_main.xml文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <com.example.testexpandablelistview.ui.StickyLayout android:id="@+id/sticky_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="0dp" android:orientation="vertical"> <LinearLayout android:id="@+id/header" android:layout_width="match_parent" android:layout_height="100dp" android:gravity="center" android:background="#78a524" android:orientation="vertical"> </LinearLayout> <LinearLayout android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> </LinearLayout> </com.example.testexpandablelistview.ui.StickyLayout> </RelativeLayout>上面的StickyLayout类就是我们自己定义的LinearLayout,思路事实上非常easy,先获取StickyLayout中的header和content两个View,代码例如以下:
private void initData(){ //使用getIdentifier()方法能够方便的获各应用包下的指定资源ID。 //具体请看:http://blog.sina.com.cn/s/blog_5da93c8f0100zlrx.html int headerId = getResources().getIdentifier("header", "id", getContext().getPackageName()); int contentId = getResources().getIdentifier("content", "id", getContext().getPackageName()); if(headerId != 0 && contentId != 0){ mHeader = findViewById(headerId); mContent = findViewById(contentId); mOriginalHeaderHeight = mHeader.getMeasuredHeight(); mHeaderHeight = mOriginalHeaderHeight; //是一个距离,表示滑动的时候,手的移动要大于这个距离才開始移动控件。再处理屏幕的监听函数mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); Log.d(TAG, "mTouchSlop = " + mTouchSlop); }else{ throw new NoSuchElementException("Did your view with \"header\" or \"content\" exist?
"); } }
@Override public boolean onInterceptTouchEvent(MotionEvent event) { int intercepted = 0; int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastXIntercept = x; mLastYIntercept = y; mLastX = x; mLastY = y; intercepted = 0; break; case MotionEvent.ACTION_MOVE: int deltaX = x - mLastXIntercept; int deltaY = y - mLastYIntercept; if(mStatus == STATUS_EXPANDED && deltaY <= -mTouchSlop){ intercepted = 1; }else if(mGiveUpTouchEventListener != null){ if(mGiveUpTouchEventListener.giveUpTouchEvent(event) && deltaY >= mTouchSlop){ intercepted = 1; } } break; case MotionEvent.ACTION_UP:{ intercepted = 0; mLastXIntercept = mLastYIntercept = 0; break; } default: break; } Log.d(TAG, "intercepted = " + intercepted); //假设为1则返回true,传递给当前的onTouchEvent。假设为0则返回false,传递给子控件 return intercepted != 0; }onInterceptTouchEvent是在ViewGroup里面定义的,用于拦截手势事件,每一个手势事件都会先调用onInterceptTouchEvent,假设该方法返回true则拦截到事件,当前的onTouchEvent会触发,假设返回false则传递给子控件。
@Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); Log.d(TAG, "x=" + x + " y=" + y + " mlastY=" + mLastY); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: int deltaX = x - mLastX; int deltaY = y - mLastY; Log.d(TAG, "mHeaderHeight=" + mHeaderHeight + " deltaY=" + deltaY + " mlastY=" + mLastY); mHeaderHeight +=deltaY; setHeaderHeight(mHeaderHeight); break; case MotionEvent.ACTION_UP: int destHeight = 0; if(mHeaderHeight <= mOriginalHeaderHeight * 0.5){ destHeight = 0; mStatus = STATUS_COLLAPSED; }else{ destHeight = mOriginalHeaderHeight; mStatus = STATUS_EXPANDED; } //慢慢滑向终点 this.smoothSetHeaderHeight(mHeaderHeight, destHeight, 500); break; default: break; } mLastX = x; mLastY = y; return true; }滑动的时候将事件传递给onTouchEvent
滑动事件中setHeaderHeight改变了上面的header部分的高度,当抬起时会推断是否改变了原始高度的一般,再慢慢滑向终点。
/* * 改变header的高度 */ private void setHeaderHeight(int height) { if(height < 0){ height = 0; } else if (height > mOriginalHeaderHeight) { height = mOriginalHeaderHeight; } if(mHeaderHeight != height || true){ mHeaderHeight = height; mHeader.getLayoutParams().height = mHeaderHeight; mHeader.requestLayout(); } }
public void smoothSetHeaderHeight(final int from, final int to, long duration) { final int frameCount = (int) (duration / 1000f * 30) + 1; final float partation = (to - from) / (float) frameCount; new Thread("Thread#smoothSetHeaderHeight") { public void ruan(){ for(int i = 0; i < frameCount; i++) { final int height; if(i == frameCount - 1){ height = to; }else{ height = (int)(from + partation * i); } post(new Runnable() { @Override public void run() { setHeaderHeight(height); } }); try { sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); }上面的View.post(Runnable)方法的作用是将Runnable对象加入到UI线程中执行,从而改变header部分的高度。
StickyLayout类的完整代码例如以下:
package com.example.testexpandablelistview.ui; import java.util.NoSuchElementException; import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.LinearLayout; /** * 自己定义LinearLayout * @author 转自:http://blog.csdn.net/singwhatiwanna/article/details/25546871 * */ public class StickyLayout extends LinearLayout{ private static final String TAG = "StickyLayout"; public interface OnGiveUpTouchEnventListener{ public boolean giveUpTouchEvent(MotionEvent event); } private View mHeader; //上面部分。以下成为Header private View mContent; //以下部分 private OnGiveUpTouchEnventListener mGiveUpTouchEventListener; private int mTouchSlop; //移动的距离 //header的高度 单位:px private int mOriginalHeaderHeight; //Header部分的原始高度 private int mHeaderHeight; //Header部分如今的实际高度(随着手势滑动会变化) private int mStatus = STATUS_EXPANDED; //当前的状态 public static final int STATUS_EXPANDED = 1; //展开状态 public static final int STATUS_COLLAPSED = 2; //闭合状态 //分别记录上次滑动的坐标 private int mLastX = 0; private int mLastY = 0; //分别记录上次滑动的坐标(onInterceptTouchEvent) private int mLastXIntercept = 0; private int mLastYIntercept = 0; /* * 构造函数1 */ public StickyLayout(Context context){ super(context); } /* * 构造函数2 */ public StickyLayout(Context context, AttributeSet attrs) { super(context, attrs); } /* 构造函数3 * TargetApi 标签的作用是使高版本号的api代码在低版本号sdk不报错 */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public StickyLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * onWindowFocusChanged方法用于监听一个activity是否载入完成。Activity生命周期中, * onStart, onResume, onCreate都不是真正visible的时间点,真正的visible时间点是onWindowFocusChanged()函数被执行时。 */ @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); //假设是activity载入完成,mHeader和mContent未被初始化。则执行初始化方法。 if(hasWindowFocus && (mHeader == null || mContent == null)){ initData(); } } private void initData(){ //使用getIdentifier()方法能够方便的获各应用包下的指定资源ID。 //具体请看:http://blog.sina.com.cn/s/blog_5da93c8f0100zlrx.html int headerId = getResources().getIdentifier("header", "id", getContext().getPackageName()); int contentId = getResources().getIdentifier("content", "id", getContext().getPackageName()); if(headerId != 0 && contentId != 0){ mHeader = findViewById(headerId); mContent = findViewById(contentId); mOriginalHeaderHeight = mHeader.getMeasuredHeight(); mHeaderHeight = mOriginalHeaderHeight; //是一个距离。表示滑动的时候,手的移动要大于这个距离才開始移动控件。 mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); Log.d(TAG, "mTouchSlop = " + mTouchSlop); }else{ throw new NoSuchElementException("Did your view with \"header\" or \"content\" exist?"); } } @Override public boolean onInterceptTouchEvent(MotionEvent event) { int intercepted = 0; int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastXIntercept = x; mLastYIntercept = y; mLastX = x; mLastY = y; intercepted = 0; break; case MotionEvent.ACTION_MOVE: int deltaX = x - mLastXIntercept; int deltaY = y - mLastYIntercept; if(mStatus == STATUS_EXPANDED && deltaY <= -mTouchSlop){ intercepted = 1; }else if(mGiveUpTouchEventListener != null){ if(mGiveUpTouchEventListener.giveUpTouchEvent(event) && deltaY >= mTouchSlop){ intercepted = 1; } } break; case MotionEvent.ACTION_UP:{ intercepted = 0; mLastXIntercept = mLastYIntercept = 0; break; } default: break; } Log.d(TAG, "intercepted = " + intercepted); //假设为1则返回true,传递给当前的onTouchEvent。假设为0则返回false,传递给子控件 return intercepted != 0; } @Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); Log.d(TAG, "x=" + x + " y=" + y + " mlastY=" + mLastY); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: int deltaX = x - mLastX; int deltaY = y - mLastY; Log.d(TAG, "mHeaderHeight=" + mHeaderHeight + " deltaY=" + deltaY + " mlastY=" + mLastY); mHeaderHeight +=deltaY; setHeaderHeight(mHeaderHeight); break; case MotionEvent.ACTION_UP: int destHeight = 0; if(mHeaderHeight <= mOriginalHeaderHeight * 0.5){ destHeight = 0; mStatus = STATUS_COLLAPSED; }else{ destHeight = mOriginalHeaderHeight; mStatus = STATUS_EXPANDED; } //慢慢滑向终点 this.smoothSetHeaderHeight(mHeaderHeight, destHeight, 500); break; default: break; } mLastX = x; mLastY = y; return true; } public void smoothSetHeaderHeight(final int from, final int to, long duration) { final int frameCount = (int) (duration / 1000f * 30) + 1; final float partation = (to - from) / (float) frameCount; new Thread("Thread#smoothSetHeaderHeight") { public void ruan(){ for(int i = 0; i < frameCount; i++) { final int height; if(i == frameCount - 1){ height = to; }else{ height = (int)(from + partation * i); } post(new Runnable() { @Override public void run() { setHeaderHeight(height); } }); try { sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } /* * 改变header的高度 */ private void setHeaderHeight(int height) { if(height < 0){ height = 0; } else if (height > mOriginalHeaderHeight) { height = mOriginalHeaderHeight; } if(mHeaderHeight != height || true){ mHeaderHeight = height; mHeader.getLayoutParams().height = mHeaderHeight; mHeader.requestLayout(); } } }MainActivity.java
package com.example.testexpandablelistview; import android.app.Activity; import android.os.Bundle; import com.example.testexpandablelistview.ui.StickyLayout; public class MainActivity extends Activity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }执行效果:
原文地址:http://blog.csdn.net/singwhatiwanna/article/details/25546871
版权声明:本文博主原创文章。博客,未经同意不得转载。
标签:
原文地址:http://www.cnblogs.com/lcchuguo/p/4911960.html