【Android】Android自定义ViewGroup

来源:互联网 发布:oppoa209软件下载 编辑:程序博客网 时间:2024/04/30 17:55

ViewGroup存在的目的就是对其子View进行管理,为其子View添加显示、响应的规则。因此,自定义ViewGroup通常需要重写onMeasure()方法对其子View进行测量,重写onLayout()方法来确定子View的位置,重写onTouchEvent()方法增加响应事件。所以我们需要做这几件事:

  • 重写onMeasure()方法对其子View进行测量
  • 重写onLayout()方法来确定子View的位置
  • 重写onTouchEvent()方法增加响应事件

以一个粘性View效果作为示例,来看看每部分都需要怎么做。先看完整版代码,后面会进一步分析:

package com.wondertwo.app.customview;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.Scroller;/** * 实现粘性效果,即当子View向上滑动大于某值后,松开手指它将向上滑动并显示下一个子View * 当滑动距离小于某值,松开手指后它将回到开始的位置 * * Created by wondertwo on 2016/2/27. */public class SticklyView extends ViewGroup {private int mScreenHeight;private Scroller mScroller;private int mLastY;private int mStart;private int mEnd;public SticklyView(Context context) {    super(context);}public SticklyView(Context context, AttributeSet attrs) {    super(context, attrs);}public SticklyView(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);}/** * 重写onMeasure()方法,通过遍历子View来测量子View的大小 * * @param widthMeasureSpec * @param heightMeasureSpec */@Overrideprotected 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);    }}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {    int childCount  = getChildCount();    // 设置ViewGroup的高度,高度等于每个子View的高度乘以子View的个数    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) {            // public void layout(int left, int top, int right, int bottom)设置child的位置            child.layout(l, i * mScreenHeight, r, (i + 1) *mScreenHeight);        }    }}/** * 手指触摸动作的监听 * * @param event * @return */@Overridepublic 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();            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;}@Overridepublic void computeScroll() {    super.computeScroll();    if (mScroller.computeScrollOffset()) {        scrollTo(0, mScroller.getCurrY());        postInvalidate();    }}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;    }  }}
  • 重写onMeasure()方法对其子View进行测量先要获得子View的数量:int count = getChildCount()。然后通过for循环遍历每个子View获得他们的大小。代码如下:

    @Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {int childCount  = getChildCount();// 设置ViewGroup的高度,高度等于每个子View的高度乘以子View的个数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) {        // public void layout(int left, int top, int right, int bottom)设置child的位置        child.layout(l, i * mScreenHeight, r, (i + 1) *mScreenHeight);    }}}
  • 重写onLayout()方法来确定子View的位置和重写onTouchEvent()方法增加响应事件了。其实这一步才是实现粘效果的关键。代码如下:

    /** * 手指触摸动作的监听 * * @param event * @return */@Overridepublic 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();        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;}

0 0
原创粉丝点击