Android控件架构与自定义控件详解(三)——自定义ViewGroup
2016-05-15 18:36
597 查看
ViewGroup存在的目的就是为了对其子View进行管理,为其子View添加显示、响应的规则。因此,自定义ViewGroup通常需要重写onMeasure()方法来对子View进行测量,重写onLayout()方法来确定子View的位置,重写onTouchEvent()方法增加响应事件。
本例将实现一个类似Android原生控件ScrollView的自定义ViewGroup,且在滑动的过程中,增加一个粘性的效果,效果图如下:
代码如下:
代码地址
本例将实现一个类似Android原生控件ScrollView的自定义ViewGroup,且在滑动的过程中,增加一个粘性的效果,效果图如下:
代码如下:
package com.example.huangfei.myapplication; import android.content.Context; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.Scroller; /** * Created by huangfeihong on 2016/5/15. * 具有粘性效果的ScrollView * 先让自定义ViewGroup实现类似ScrollView的功能,再添加粘性效果 */ public class MyScrollView extends ViewGroup { private int mScreenHeight; private Scroller mScroller; private int mLastY; private int mStart; private int mEnd; public MyScrollView(Context context) { super(context); initView(context); } public MyScrollView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } private void initView(Context context) { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); mScreenHeight = metrics.heightPixels; //让每个子View都显示完整的一屏 mScroller = new Scroller(context); } /** * 先对其子View进行测量 * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int count = getChildCount(); for (int i = 0; i < count; i++) { View childView = getChildAt(i); measureChild(childView, widthMeasureSpec, heightMeasureSpec); } } /** * 对其子View进行放置位置的设定 * @param changed * @param l * @param t * @param r * @param b */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childCount = getChildCount(); // 设置ViewGroup的高度 MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams(); mlp.height = childCount * mScreenHeight; setLayoutParams(mlp); //让每个子View依次下排 for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); if(childView.getVisibility() != View.GONE){ childView.layout(l, i * mScreenHeight, r, (i + 1) * mScreenHeight); } } } /** * 在ViewGroup中添加滑动事件,可以使用scrollBy()方法来辅助滑动 * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { int y = (int) event.getY(); switch (event.getAction()){ case MotionEvent.ACTION_DOWN: mLastY = y; //记录触摸起点 mStart = getScrollY(); break; case MotionEvent.ACTION_MOVE: if(!mScroller.isFinished()){ mScroller.abortAnimation(); } int dy = mLastY - y; if(getScrollY() < 0 && dy < 0) dy = 0; if(getScrollY() > getHeight() - mScreenHeight && dy > 0) dy = 0; scrollBy(0, dy); mLastY = y; break; case MotionEvent.ACTION_UP: //记录触摸终点 //mEnd = getScrollY(); //int dScrollY = mEnd - mStart; int dScrollY = checkAlignment(); //实现粘性效果,滑动距离大于子View的1/3,则使用Scroller类来平滑到下一个子View,否则就会回滚 //到原来的位置 if(dScrollY > 0){//向上滑动 if(dScrollY < mScreenHeight / 3){ mScroller.startScroll(0, getScrollY(), 0, -dScrollY); }else{ mScroller.startScroll(0, getScrollY(), 0, mScreenHeight - dScrollY); } }else{//向下滑动 if(-dScrollY < mScreenHeight / 3){ mScroller.startScroll(0, getScrollY(), 0, -dScrollY); }else{ mScroller.startScroll(0, getScrollY(), 0, - mScreenHeight - dScrollY); } } break; } postInvalidate(); return true; } /** * 获取手指滑动的距离 * @return */ private int checkAlignment() { int mEnd = getScrollY(); boolean isUp = ((mEnd - mStart) > 0) ? true : false; int lastPrev = mEnd % mScreenHeight; int lastNext = mScreenHeight - lastPrev; if (isUp) { //向上的 return lastPrev; } else { return -lastNext; } } @Override public void computeScroll() { super.computeScroll(); if(mScroller.computeScrollOffset()){ scrollTo(0, mScroller.getCurrY()); postInvalidate(); } } }
代码地址
相关文章推荐
- Java应用架构的演化之路
- hive介绍
- IOS开发必读博客网站
- Dubbo学习之目录
- [架构设计]第一讲:什么是架构
- DRBD+Heartbeat+Mysql 高可用实战
- iOS架构谈
- Win7下用IIS发布网站
- Android源码在线阅读网站
- C#做完一个网站怎么发布?
- 打开网站php出现乱码问题的解决办法以及无法显示验证码
- 初步掌握Yarn的架构及原理
- 制作网站二维码
- iscsi和gfs2群集文件系统
- MySQL高可用之MHA—其它高可用解决方案和问题
- 初步掌握Yarn的架构及原理
- 系统架构师-基础到企业应用架构-系列索引
- 如何成为优秀的架构师
- 北京市工作居住证官方网站js报错不能使用解决办法
- 如何下载YouTube网站的视频