自定义View总结


自定义View一般可以分为四类:
1、继承View重写onDraw()方法
为了实现一些不规则的效果,需要重写onDraw()方法
这种方式需要自己支持wrap_content和padding

2、继承ViewGroup派生特殊的Layout
需要自己处理ViewGroup的测量、布局的过程

3、继承特定的View(比如TextView)
不需要自己支持wrap_content和padding

4、继承特定的ViewGroup(比如LiearLayout)
不需要自己处理ViewGroup的测量、布局的过程
一般情况下第二种方式能实现的效果,第四种也是可以的

注意事项:
1、让View支持wrap_content,重写onMeasure()
    protected void onMeasure ( int widthMeasureSpec , int heightMeasureSpec) {
    super .onMeasure(widthMeasureSpec , heightMeasureSpec) ;
    int widthSpecMode = MeasureSpec. getMode (widthMeasureSpec) ;
    int widthSpecSize = MeasureSpec. getSize (widthMeasureSpec) ;
    int heightSpecMode = MeasureSpec. getMode (heightMeasureSpec) ;
    int heightSpecSize = MeasureSpec. getSize (heightMeasureSpec) ;
    if (widthSpecMode == MeasureSpec. AT_MOST
            && heightSpecMode == MeasureSpec. AT_MOST ) {
        setMeasuredDimension( 200 , 200 ) ;
    } else if (widthSpecMode == MeasureSpec. AT_MOST ) {
        setMeasuredDimension( 200 , heightSpecSize) ;
    } else if (heightSpecMode == MeasureSpec. AT_MOST ) {
        setMeasuredDimension(widthSpecSize , 200 ) ;
    }
}
其他情况仍交由super.onMeasure()处理,当wrap_content的时候(即SpecMode为AT_MOST)给相应的宽或高设置一个固定值,如本例中的200

2、如果有必要,让View支持padding(layout_margin由父容器控制)
在onDraw()方法中,通过getPadding()获取padding值,然后在设置图形宽高等属性时考虑padding的值就行了,如:
width = getWidth - paddingLeft - paddingRight;

3、没有必要在View中使用Handler,因为View中提供了一系列的post方法

4、当Veiw变得不可见时,需要及时停止线程和动画,否则有可能会造成内存泄露
一般在onDetachedFromWindow()中进行处理

5、View带有滑动嵌套时,需要处理好滑动冲突
方法一(外部拦截法):重写onInterceptTouchEvent()
// 分别记录上次滑动的坐标(onInterceptTouchEvent)
private int mLastXIntercept = 0;
private int mLastYIntercept = 0;
@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean intercepted = false;
        int x = (int) ev.getX();
        int y = (int) ev.getY();

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                intercepted = false;
                break;
            case MotionEvent.ACTION_MOVE: {
                int deltaX = x - mLastXIntercept;
                int deltaY = y - mLastYIntercept;
                if (父容器需要当前点击事件) { //如:Math.abs(deltaX) > Math.abs(deltaY)
                    intercepted = true;
                } else {
                    intercepted = false;
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                intercepted = false;
                break;
            }
        }
        mLastXIntercept = x;
        mLastYIntercept = y;
        return intercepted;
    }

方法二(内部拦截法):对dispatchTouchEvent()进行重写,并且配合getParent().requestDisallowInterceptTouchEvent(true)
// 分别记录上次滑动的坐标(onInterceptTouchEvent)
    private int mLastXIntercept = 0;
    private int mLastYIntercept = 0;
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        int x = (int) ev.getX();
        int y = (int) ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                int deltaX = x - mLastXIntercept;
                int deltaY = y - mLastYIntercept;
                if (父容器需要当前点击事件) {    //如:Math.abs(deltaX) > Math.abs(deltaY)
                    getParent().requestDisallowInterceptTouchEvent(false);
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                getParent().requestDisallowInterceptTouchEvent(false);
                break;
            }
        }
        mLastXIntercept = x;
        mLastYIntercept = y;
        return super.dispatchTouchEvent(ev);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值