自定义View总结

    xiaoxiao2022-06-29  40

     自定义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);     }
    转载请注明原文地址: https://ju.6miu.com/read-1125307.html

    最新回复(0)