安卓复习之旅—自定义view(二)

来源:互联网 发布:matlab for mac 2016 编辑:程序博客网 时间:2024/04/29 22:44

今天来看一下继承自ViewGroup的自定义view;看看效果先:
这里写图片描述
有点像垂直方向的viewpager吧,下面来一步一步实现它吧。
step1声明需要的一些成员变量

    // 屏幕高度    private int mScreenHeight;    private int mScrollStart;    private int mScrollEnd;    // 移动时的Y距离    private int mLastY;    // 滚动辅助类    private Scroller mScroller;    private boolean isScrolling;    // 加速度检测    private VelocityTracker mVelocityTracker;    private int currentPage = 0;    private onPageChangeListener mOnPageChangeListener;    private static final String TAG = "VerticalLinearLayout";

其中VelocityTracker 主要用跟踪触摸屏事件(flinging事件和其他gestures手势事件)的速率。用addMovement( MotionEvent)函数将Motion event加入到VelocityTracker类实例中.你可以使用getXVelocity() 或getXVelocity()获得横向和竖向的速率到速率时,但是使用它们之前请先调用computeCurrentVelocity(int) 来初始化速率的单位 。
onPageChangeListener 是自定义的回调接口

/**     * 设置回调接口     */    public void SetOnPageChangeListener(onPageChangeListener listener) {        this.mOnPageChangeListener = listener;    }    public interface onPageChangeListener {        void onPageChange(int currentPage);    }

step2 在构造方法中初始化成员变量

// 获取屏幕的高度        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        DisplayMetrics dm = new DisplayMetrics();        wm.getDefaultDisplay().getMetrics(dm);        mScreenHeight = dm.heightPixels;        Log.e(TAG, "mScreenHeight=  " + mScreenHeight);        mScroller = new Scroller(context);

step3在onMeasure()方法中计算每个子view的尺寸

    int count = getChildCount();        for (int i = 0; i < count; i++) {            Log.e(TAG, "count=  " + count);            View childView = getChildAt(i);            measureChild(childView, widthMeasureSpec, heightMeasureSpec);        }

step4在onLayout()中确定子view的位置

    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        // TODO Auto-generated method stub        if (changed) {            int count = getChildCount();            // 设置主布局的高度                     MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();            mlp.height = mScreenHeight * count;            setLayoutParams(mlp);            // 设置每个子布局的位置            for (int i = 0; i < count; i++) {                View childView = getChildAt(i);                if (childView.getVisibility() != View.GONE) {                    childView.layout(l, i * mScreenHeight, r, (i + 1) * mScreenHeight);                }            }        }    }

onLayout的几个参数说明: 1)参数changed表示view有新的尺寸或位置; 2)参数l表示相对于父view的Left位置; 3)参数t表示相对于父view的Top位置; 4)参数r表示相对于父view的Right位置; 5)参数b表示相对于父view的Bottom位置。.
MarginLayoutParams是继承自ViewGroup.LayoutParams
子类有 FrameLayout.LayoutParams,LinearLayout.LayoutParams, RelativeLayout.LayoutParams
step5 处理触摸事件

    // 如果正在滑动,不做处理,调用父类的触摸事件        Log.e(TAG, "isScrolling=" + isScrolling);        if (isScrolling) {            return super.onTouchEvent(event);        }        initVelocityTracker(event);        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:            // Return the scrolled top position of this view            mScrollStart = getScrollY();            mLastY = (int) event.getY();            break;        case MotionEvent.ACTION_MOVE:            if (!mScroller.isFinished()) {                // Stops the animation.                mScroller.abortAnimation();            }            int dy = mLastY - (int) event.getY();            int scrollY = getScrollY();            // 已经到达顶端            if (dy < 0 && scrollY + dy < 0) {                dy = -scrollY;//此时dy=0            }            // 已经到达底部            if (dy > 0 && scrollY + dy > getHeight() - mScreenHeight) {                dy = getHeight() - mScreenHeight - scrollY;//此时dy=0            }            scrollBy(0, dy);            mLastY = (int) event.getY();            break;        case MotionEvent.ACTION_UP:            mScrollEnd = getScrollY();            Log.e(TAG, "mScrollStart=" + mScrollStart);            Log.e(TAG, "mScrollEnd=" + mScrollEnd);            int dScrollY = mScrollEnd - mScrollStart;            if (dScrollY > 0) {// 往上滑动                if (shouldScrollToNext(dScrollY)) {                    mScroller.startScroll(0, getScrollY(), 0, mScreenHeight - dScrollY);                } else {                    mScroller.startScroll(0, getScrollY(), 0, -dScrollY);                }            } else {// 往上滑                if (shouldScrollToPre(dScrollY)) {                    mScroller.startScroll(0, getScrollY(), 0, -mScreenHeight - dScrollY);                } else {                    mScroller.startScroll(0, getScrollY(), 0, -dScrollY);                }            }            isScrolling = true;            postInvalidate();            //回收资源            recycleVelocity();            break;        }        return true;

step6需要重写computeScroll()方法
为了易于控制滑屏控制,Android框架提供了 computeScroll()方法去控制这个流程。在绘制View时,会在draw()过程调用该 方法。因此, 再配合使用Scroller实例,我们就可以获得当前应该的偏移坐,手动使View/ViewGroup偏移至该处。

    @Override    public void computeScroll() {        // TODO Auto-generated method stub        super.computeScroll();        // If it returns true, the animation is not yet finished.\        Log.e(TAG, "mScroller.computeScrollOffset()=" + mScroller.computeScrollOffset());        if (mScroller.computeScrollOffset()) {// 滑动结束的时候调用scrollTo()            scrollTo(0, mScroller.getCurrY());            postInvalidate();        } else {            int position = getScrollY() / mScreenHeight;            Log.e(TAG, "position=" + position + ",currentPage=" + currentPage);            if (position != currentPage) {                if (mOnPageChangeListener != null) {                    currentPage = position;                    mOnPageChangeListener.onPageChange(currentPage);                }            }            isScrolling = false;        }    }

一些小方法:

    /**     * 释放资源     */    private void recycleVelocity() {        // TODO Auto-generated method stub        if (mVelocityTracker != null) {            mVelocityTracker.recycle();            mVelocityTracker = null;        }    }    /**     * 初始化加速度追踪器     *      * @param event     */    private void initVelocityTracker(MotionEvent event) {        // TODO Auto-generated method stub        if (mVelocityTracker == null) {            mVelocityTracker = VelocityTracker.obtain();        }        mVelocityTracker.addMovement(event);    }    /**     * 滑动到下一页     *      * @param dScrollY     * @return     */    private boolean shouldScrollToNext(int dScrollY) {        // TODO Auto-generated method stub        return dScrollY > mScreenHeight / 2 || Math.abs(getVelocity()) > 600;    }    /**     * 滑动到上一页     *      * @param dScrollY     * @return     */    private boolean shouldScrollToPre(int dScrollY) {        // TODO Auto-generated method stub        return -dScrollY > mScreenHeight / 2 || Math.abs(getVelocity()) > 600;    }    /**     * 获取Y方向的加速度     * @return     */    private double getVelocity() {        // TODO Auto-generated method stub        mVelocityTracker.computeCurrentVelocity(1000);        return (int) mVelocityTracker.getYVelocity();    }

至此,基本工作就完成了;
看看MainActivity

mMianLayout = (VerticalLinearLayout) findViewById(R.id.id_main_ly);        mMianLayout.SetOnPageChangeListener(this);    @Override    public void onPageChange(int currentPage) {        // TODO Auto-generated method stub        Toast.makeText(MainActivity.this, "第" + (currentPage + 1) + "页", Toast.LENGTH_SHORT).show();    }

下载地址:http://download.csdn.net/my

0 0
原创粉丝点击