菜鸟进阶笔记|初探自定义View|05|自定义ViewGroup

标签: 自定义ViewGroup
8人阅读 评论(0) 收藏 举报
分类:

类似ScrollView的滑动,并附加黏性效果

自定义View中代码如下:

public class MyScrollView extends ViewGroup {
    private static final String TAG = "MyScrollView";
    private Scroller mScroller;
    private int mScreenHeight;    //获取屏幕高度
    int mLastY = 0;
    int mStart = 0;

    public MyScrollView(Context context) {
        super(context);
    }

    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScroller = new Scroller(context);
        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        mScreenHeight = wm.getDefaultDisplay().getHeight(); //记录设备屏幕高度
    }

    public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 在ViewGroup能够滚动之前,需要先放置好它的子View。使用遍历的方式来通知子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);
            //要求其子View根据此View测量自己
            measureChild(childView, widthMeasureSpec, heightMeasureSpec);
        }
    }

    /**
     * 接下来就要对子View进行放置位置的设定。我们让每个子View都显示完整的一屏,方便后续操作。
     * 在放置子View前,需要确定整个ViewGroup的高度。
     * 在获取了整个ViewGroup的高度之后,就可以通过遍历来设定每个子View需要放置的位置了
     * 直接通过调用子View的Layout()方法,并将具体的位置座位参数传递进去即可,代码如下所示。
     * 在本例中由于让每个子View都占一屏的高度,因此整个ViewGroup的高度即子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 = mScreenHeight * childCount;
        setLayoutParams(mlp);
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
            if (child.getVisibility() != View.GONE) {
                child.layout(   //给子View设置位置
                        l,
                        i * mScreenHeight,
                        r,
                        (i + 1) * mScreenHeight
                );
            }
        }
    }

    @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() > mScreenHeight) {
                    dy = 0;
                }
                scrollBy(0, dy);
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
                //当手指离开后,如果手指滑动超过一定距离,则平滑到下一个View,如果小于一定距离,则回滚到原来的位置。
                int mEnd = getScrollY();
                int dScrollY = mEnd - mStart;
                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;
        }
        invalidate();
        return true;
    }

    //该回调在执行invalidate()方法时会执行
    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {  //判断是否已终止滚动
            scrollTo(0, mScroller.getCurrY());
            postInvalidate();
        }
    }
}

在xml中如下使用:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.myview.myview.MyScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorAccent" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary" />
    </com.example.myview.myview.MyScrollView>
</LinearLayout>

就不贴效果图啦,跑一下就知道了(#^.^#)

查看评论

对比自定义view和自定义viewgroup

view 的onDraw()和ViewGroup的dispatchDraw()方法最近在研究view的整个事件过程,以及自定义view的绘制,今天突然发现还有dispatchDraw(),于是在官方a...
  • outdoorsmanm
  • outdoorsmanm
  • 2016-03-17 18:35:12
  • 1636

Android自定义View或ViewGroup的流程

对于onMeasure()方法-->不论是View还是ViewGroup,onMeasure方法其实都是在测量自身的宽和高,只是对于ViewGroup来讲,当该ViewGroup的父容器为其设置的计算...
  • shakespeare001
  • shakespeare001
  • 2016-04-07 21:09:19
  • 1923

android之自定义View和ViewGroup(二)(此篇不讲述代码,只讲述原理和结构,带你走进自定义的世界)

上一篇(android之自定义View和ViewGroup分析(一))中已经讲过了关于自定义View的实现原理以及实现步骤和相关的方法分析,所以这篇就不讲自定义View了,讲讲自定义ViewGroup...
  • gsw333
  • gsw333
  • 2016-07-13 17:07:03
  • 487

了解自定义View和继承View,继承ViewGroup,继承已有View,继承已有ViewGroup实例ji

自定义View的分类 继承View 当我们需要实现的效果是一个不规则效果的时候,那么这时就需要继承 View 来实现了,我们需要重写 onDraw 方法,在该方法里实现各种不规则的图形和效果。当我...
  • github_37217206
  • github_37217206
  • 2017-02-06 10:25:59
  • 947

自定义ViewGroup和其子View

ViewGroup 初始化计算width,height。顺序如下05-13 13:41:57.649 D/GestureLockFred(32644): onMeasure 05-13 13:41:...
  • laisse
  • laisse
  • 2016-05-18 11:57:45
  • 1714

自定义View绘制心得(自定义view和自定义viewGroup)

自定义view和viewGroup 的差异和方法
  • cuizehui123
  • cuizehui123
  • 2016-03-09 21:17:34
  • 880

自定义View事件拦截机制(自定义viewGroup和外部法解决滑动冲突)

view事件的分发机制,和滑动冲突的处理
  • cuizehui123
  • cuizehui123
  • 2016-03-14 22:17:06
  • 2781

android之自定义viewGroup仿scrollView详解

相信学了安卓的朋友都知道自定义viewGroup离不开重写onmeasure()和onLayout(),开始讲解代码之前,先来看看与这两个方法相关知识:    一、onMeasure() :这是测量自...
  • zhongwn
  • zhongwn
  • 2016-07-21 17:53:30
  • 2807

自定义view/viewgroup/流布局(极简版)

1自定义view 1)构造器private String text; private int mTitleTextSize; private Rect mBound; private Paint m...
  • mwh613245
  • mwh613245
  • 2016-06-12 17:08:28
  • 304

自定义控件(15)---ViewGroup绘制的自定义子View的margin注意

activity_main.xml
  • u013210620
  • u013210620
  • 2015-11-15 14:02:14
  • 2215
    个人资料
    等级:
    访问量: 1773
    积分: 99
    排名: 126万+
    文章分类
    文章存档