Android之自定义ViewGroup

先来看一下下面的几个函数

<span style="font-family:Microsoft YaHei;font-size:18px;">        //获得WindowManager实例,主要用来管理窗口的一些状态、属性、view增加、删除、更新、窗口顺序、消息收集和处理等
         WindowManager wm=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        //获取手机分辨率类的实例对象
        DisplayMetrics dm=new DisplayMetrics();
        Log.i("info",dm.toString());
        //将当前窗口的信息放到对象dm中
        wm.getDefaultDisplay().getMetrics(dm);

        Log.i("info",dm.toString());</span>

其中有两个Log,主要是用来见证wm.getDefaultDisplay().getMetrics(dm)的作用的

dm就是管理着手机界面的一些信息

第一个Log的信息如下:

DisplayMetrics{density=0.0, width=0, height=0, scaledDensity=0.0, xdpi=0.0, ydpi=0.0}

第二个Log的信息如下:

DisplayMetrics{density=2.0, width=720, height=1280, scaledDensity=2.0, xdpi=345.056, ydpi=342.231}


接着看一下将要自定义的ViewGroup的布局文件,也就是activity将要载入的

<com.example.administrator.viewgroupdemo.MyScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:src="@drawable/test1" />

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:src="@drawable/test2" />

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:src="@drawable/test3" />

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:src="@drawable/test4" />

    </com.example.administrator.viewgroupdemo.MyScrollView>

注意上面的每一个子ImageView的高度都是match_parent


下面是自定义ViewGroup部分

按照常规,对子视图进行布局,其中的onMeasure()并没有起到什么作用

/*
在调用onLayout的时候应该先调用onMeasure方法去测量子View
关于onLayout这个方法,只有是继承ViewGroup才要重载,要分配子view的位置
这个必须写,不然子视图将不会展示
 */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount=getChildCount();
        //获取LayoutParams
        MarginLayoutParams mlp=(MarginLayoutParams)getLayoutParams();
        //指定LayoutParams的高度为子view高度之和
        mlp.height=mScreenHeight*childCount;
        //设置
        setLayoutParams(mlp);
        for(int i=0;i<childCount;i++){
            View child=getChildAt(i);
            if(child.getVisibility()!=View.GONE){
                //为每一个子View布局
                child.layout(l,i*mScreenHeight,r,(i+1)*mScreenHeight);
            }
        }
    }

    /**
     * 当我删除这个函数的时候,并没有对整个视图造成影响
     * @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);
        }
    }

布局建好后,下面是触摸事件

其中注释的结果是我一点一点试出来的,如果对getScrollY()不了解,理解代码会很繁琐的

@Override
    public boolean onTouchEvent(MotionEvent event) {
        int y=(int)event.getY();
        switch(event.getAction()){
            //触摸时操作
            case MotionEvent.ACTION_DOWN:
                mLastY=y;
                //获得移动的Y的距离
                mStart=getScrollY();
                break;
            //移动时操作
            case MotionEvent.ACTION_MOVE:
                //如果没有滚动完成,停止动画
                if(!mScroller.isFinished()){
                    mScroller.abortAnimation();//停止动画
                }
                int dy=mLastY-y;
                //这个if语句是判断是否到了顶部,如果是,则不移动
                if(getScrollY()<0){
                    Log.i("info","顶部"+getScrollY());
                    dy=0;
                }
                //getHeight指的是整个自定义S从roller的高度,
                //mScreenHeight是一个imageView的高度
                //如果当前滑动的位置已经是最后一张图片了,停止移动
                if(getScrollY()>getHeight()-mScreenHeight){
                    Log.i("info","底部"+getScrollY());
                    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;
    }
    //获取从接触开始到离开时的移动距离,有正负之分,lastNext就是为了获取向下滑动时相对于Scroller的距离
    private int checkAlignment() {
        int mEnd = getScrollY();
        boolean isUp = ((mEnd - mStart) > 0) ? true : false;
        //因为getScrollY()获取的值是针对整个Scroller的,而Scroller包含了几个ImageView
        int lastPrev = mEnd % mScreenHeight;
        int lastNext = mScreenHeight - lastPrev;
        if (isUp) {
            //向上的
            return lastPrev;
        } else {
            return -lastNext;
        }
    }

    /**
     * 不太理解,但是删除该方法就会出问题
     * 当startScroll执行过程中即在duration时间内,
     * computeScrollOffset  方法会一直返回false,
     * 但当动画执行完成后会返回返加true
     */
    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {
            scrollTo(0, mScroller.getCurrY());
           postInvalidate();
        }
    }

关于startScroll()函数,见 http://ipjmc.iteye.com/blog/1615828

最后一个函数见http://blog.csdn.net/chenzhiqin20/article/details/8811428


就先说到这里


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值