博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android自己定义组件系列【5】——高级实践(1)
阅读量:7052 次
发布时间:2019-06-28

本文共 10283 字,大约阅读时间需要 34 分钟。

在接下来的几篇文章将任老师的博文《》骤来具体实现。来学习一下大神的代码并记录一下。

原文出处:http://blog.csdn.net/singwhatiwanna/article/details/25546871

先看一下终于效果:

新建一个activity_main.xml文件

上面的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);	}}
执行效果:

版权声明:本文博主原创文章。博客,未经同意不得转载。

你可能感兴趣的文章
【LeetCode】107. Binary Tree Level Order Traversal II (2 solutions)
查看>>
《微软的软件测试之道》读书笔记 之 结构测试技术
查看>>
ASP.NET中Session的个人浅谈
查看>>
数学图形之Kuen Surface
查看>>
ORACLE里锁有以下几种模式,v$locked_object,locked_mode
查看>>
【树莓派】Linux 测网速及树莓派源
查看>>
Java用户线程和守护线程
查看>>
[TypeScript] Use the never type to avoid code with dead ends using TypeScript
查看>>
Javascript 与 SPA单页Web富应用
查看>>
SpringMVC之访问静态文件
查看>>
【java设计模式】之 模板方法(Template Method)模式
查看>>
小米手机会不会更好
查看>>
atitit.Sealink2000国际海运信息管理系统
查看>>
android面试总结01 activity生命周期
查看>>
Java 实现策略(Strategy)模式
查看>>
Ubuntu离线安装Sogou拼音(附老版本安装&输入法自启动)
查看>>
springmvc结合base64存取图片到mysql
查看>>
深度学习主机环境配置: Ubuntu16.04+GeForce GTX 1080+TensorFlow
查看>>
linux 抓包 tcpdump 简单应用
查看>>
mongodb官网文档阅读笔记:与写性能相关的几个因素
查看>>