Android控件架构与自定义控件详解(三)自定义ViewGroup
2017-02-02 18:18
381 查看
之前分析了如何自定义View,下面来分析如何创建自定义ViewGroup,ViewGroup存在的目的就是为了对其子View进行管理,为其子View添加显示、响应的规则。因此,自定义ViewGroup通常需要重写onMeasure()方法来对子View进行测量,重写onLayout()方法来确定子View的位置,重写onTouchEvent()方法增加响应事件。
下面将实现一个类似Android原生控件ScrollView的自定义ViewGroup,并且在滑动的过程中,增加一个黏性效果,即滑动大于一定的距离才会触发正常滑动,否则自动弹回开始的位置,效果图如下:
代码如下:
代码下载
下面将实现一个类似Android原生控件ScrollView的自定义ViewGroup,并且在滑动的过程中,增加一个黏性效果,即滑动大于一定的距离才会触发正常滑动,否则自动弹回开始的位置,效果图如下:
代码如下:
package com.example.customviewgroup; 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.view.WindowManager; import android.widget.Scroller; /** * Created by gavinandre on 17-1-29. */ public class MyScrollView extends ViewGroup { private int mScreenHeight; private Scroller mScroller; private int mLastY; private int mStart; private int mEnd; public MyScrollView(Context context) { this(context, null); } public MyScrollView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } private void initView(Context context) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(dm); mScreenHeight = dm.heightPixels; mScroller = new Scroller(context); } /** * 使用遍历方式通知子View对自身进行测量 */ @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进行放置位置的设定 * 本例让每个View都显示完整的一屏 * 使用遍历的方式通知子View对自身进行布局设置 */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childCount = getChildCount(); //设置ViewGroup的高度 MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams(); mlp.height = mScreenHeight * childCount; setLayoutParams(mlp); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); if (child.getVisibility() != View.GONE) { //修改每个子View的top和bottom属性,让它们能依次排列下来 child.layout(l, i * mScreenHeight, r, (i + 1) * mScreenHeight); } } } /** * 在ViewGroup中添加滑动事件 * down事件记录触摸位置 * move事件使用scrollBy(0,dy)方法,实现手指滑动时所有子View跟着滑动 * up事件实现黏性效果 */ @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; } if (getScrollY() > getHeight() - mScreenHeight) { dy = 0; } scrollBy(0, dy); mLastY = y; break; case MotionEvent.ACTION_UP: 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; } /** * 获取触摸时滑动的距离 */ private int checkAlignment() { int mEnd = getScrollY(); boolean isUp = ((mEnd - mStart) > 0); 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(); } } }
代码下载
相关文章推荐
- Android控件架构与自定义控件详解(二)——自定义View
- 3.5.Android控件架构与自定义控件详解之自定义View(二)
- 3.5.Android控件架构与自定义控件详解之自定义View(四)
- Android控件架构与自定义控件详解(三)——自定义ViewGroup
- 3.5.Android控件架构与自定义控件详解之自定义View(一)
- 阅读徐宜生《Android群英传》的笔记——第3章 Android控件架构与自定义控件详解(3.1-3.5)
- Android控件架构与自定义控件详解(一)——Android控件架构与View的绘制原理
- 第三章 Android控件架构与自定义控件详解
- 3.1.Android控件架构与自定义控件详解之控件架构
- 【笔记】第三章Android控件架构与自定义控件详解(1)
- 《Android群英传》读书笔记3.Android控件架构与自定义控件详解
- 《Android群英传》阅读笔记——第三章:Android控件架构与自定义控件详解
- Android控件构架与自定义控件详解(二)自定义View
- 3.5Android控件架构与自定义控件详解之自定义View(三)
- android进阶-Android控件架构与自定义控件详解(一)
- Android 控件架构与自定义控件详解
- Android群英传知识点回顾——第三章:Android控件架构与自定义控件详解
- 3.4.Android控件架构与自定义控件详解之ViewGroup的测量与绘制
- Android控件架构与自定义控件详解
- 【笔记】第三章Android控件架构与自定义控件详解(2)