自定义View相关API

本文介绍了Android自定义View的相关API,包括onTouchEvent与onTouch的区别、onClick等事件处理,以及canvas绘图方法,如drawBitmap、drawArc等。同时讲解了测量、布局和绘制过程中的关键方法,如onMeasure、requestLayout、invalidate等,还涉及Scroller、ViewDragHelper的使用,并探讨了Touch事件的分发和拦截机制。
摘要由CSDN通过智能技术生成

-一些方法的调用

onFinishInflate: 加载布局完成之后调用

获取位置:
getX():相对于父控件
getRowX():相对于手机屏幕
getScrollX:屏幕左上角的坐标
scrollTo(x,y):移动的是手机的屏幕,参照物是(0,0)坐标
scrolBy:移动的是手机的屏幕,参照物是上次的坐标

canvas相关
canvas.drawBitmap();画bitmap
canvas.drawArc:画圆弧
canvas.drawCircle:画圆
canvas.rotate:旋转坐标系
canvas.drawLine:画线
canvas.drawOval:画椭圆
canvas.drawRect:画矩形
canvas.draw……….

-获取view宽高
getWidth(),getHeight():
值是不准确的,在Layout布局完成,调用之后赋值的
所以在layout之后调用才是准确的,

getMessureWidth,getMessureHeight:
这两个方法是在测量时候赋值的,所以在调用这两个方法的时候需要去调用测量方法onMessure().

-触发onDraw()绘制

invalidate():在主线程中执行
postvalidate():在子线程执行

-触发onLayout布局
requestLayout()

-Measure相关

onMeasure(int widthMeasureSpec, int heightMeasureSpec):
widthMeasureSpec,heightMeasureSpec是父容器给的期望,是32位的二进制数据

头两位代表期望模式:3种”:

UNSPECTED:不精确的,父容器不给限制,自己想多大就多大
EXACTLY:精确值,父容器指定200dp(后30值算出来的值),那就只能是200dp
AT_MOST:最大值,(后30位)希望的宽高最大不能超过一个值

MeasureSpec.getMode(widthMeasureSpec) 宽度的前两位值,模式
MeasureSpec.getSize(widthMeasureSpec)宽度的后30位,值

setMeassureDimension():设置自己的大小,是自己真实的大小(后30位的值)

-Scroller相关
Scroller:平缓的滑动效果
startScroll:一个点经过一段时间移动到另外一个点,只是数据的模拟变化,需要更新UI
invalidate()—->会调用computeScroll()方法

在computeScroll中移动屏幕:

public void computeScroll() {
    if (mScroller.computeScrollOfset()) {
        // 正在模拟计算数据
        scrollTo(mScroller.getCurentX(),0)
        // 不会一直invalidate()(计算完毕之后)
        invalidate();       
        }
}

-ViewDragHelper
ViewDragHelper:是suport v4包中的一个工具类,是用来分析触摸行为,
对onTouchEvent的3中触摸事件(down,move,up)做了一定的封装。

创建实例
传递参数为:分析的ViewGroup(this),触摸的回调callback

ViewDragHelper helperViewDragHelper.create(viewGroup,callback);

分析触摸事件

// 将onTouchEvent的up move down事件交给ViewDragHelper分析
protected boolean onTouchevent(Event event) {
    //分析触摸事件
    helper.processTouchEvent(event);
    // 消费事件
    return true;
}

回调方法
主要有以下几个:
tryCaptureView:捕捉的View
clampViewPositionHorizontal:down事件(水平,竖直触摸回调)
onViewPositionChanged:move事件
onViewReleased:up事件

几个方法
ViewDragHelper.smoothSlideViewTo(mDeleteView,l,0):相对于Scrollor,让View的拖动更加平缓.
ViewCompat.postInvalidateOnAnimation(SweepView.this): 相对于invalidate(),在某些机子上调用invalidate没有卵用.

private class SweepViewCallback extends ViewDragHelper.Callback {
        // 分析触摸事件
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            // child为分析的子View,分析的id标记
            return child == mContentView || child == mDeleteView;
        }
        // 分析view的水平拖地
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            // child为触摸的child,left为child的左上角到到直系父容器的左上角的距离
            Log.d("ch111","left"+left+mDeleteView.getMeasuredWidth());
            if (child == mContentView) {

                if (left < -mDeleteView.getMeasuredWidth()) {
                    left = -mDeleteView.getMeasuredWidth();
                }else if (left > 0) {
                    left = 0;
                }
            } else if (child == mDeleteView) {

                int temp = mContentView.getMeasuredWidth() - mDeleteView.getMeasuredWidth();
                if (left < temp) {
                    left = temp;
                } else if (left > mContentView.getMeasuredWidth()) {
                    left = mContentView.getMeasuredWidth();
                }
            }
            return left;
        }

        // touchEvent的move事件
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
//            ViewCompat.postInvalidateOnAnimation(SweepView.this);
            invalidate();
            if (changedView == mContentView) {

                int l = mContentView.getMeasuredWidth() + left;
                int r = mContentView.getMeasuredWidth() + left + mDeleteView.getMeasuredWidth();
                int b = mContentView.getMeasuredHeight();

                Log.d("ch---", "left  " + left);
                Log.d("ch ", "l" + l + " r" + r + " b" + b);
                mDeleteView.layout(l, 0, r, b);
//                mViewDragHelper.smoothSlideViewTo(mDeleteView,l,0);
            }else if (changedView == mDeleteView) {
                int mleft = left - mContentView.getMeasuredWidth();
                int mtop = 0;
                int mright = left;
                int mbottom = mContentView.getMeasuredHeight();
                mContentView.layout(mleft,mtop,mright,mbottom);
//                mViewDragHelper.smoothSlideViewTo(mContentView,mleft,0);
            }
            super.onViewPositionChanged(changedView, left, top, dx, dy);
        }

        public void onViewReleased(View releasedChild, float xvel, float yvel) {
        }
    }

-View的Touch事件:3个方法
dispatchTouchEvent: 分发事件
onInterceptTouchLisenter:拦截事件
onTouchEvent:消费事件

他们遵循Touch事件的流程,他们有自己的功能作用,一般不要混用(不建议),也就是不要在dispatchTouchEvent,onInterceptTouchLisenter处理触摸的逻辑.
onTouch与onTouchEvent的区别:

setonTouchListener–>onTouch:看源码,在diapatchTouchEvent调用
onTouchEvent:在onInterceptTouchListener

OnClick,OnLongClick,onTouch
onTouch:
    setonTouchListener-->onTouch,是在diapatchTouchListener调用.
OnClick:
    setOnClickListener-->onTouchEvent:ACTION_UP-->performClick-->OnClickListener.onClick(this),在up事件之后调用
OnLongClick:
    setOnLongClickListener-->onTouchEvent:ACTION_DOWN-->performLongClick-->OnLongClickListener.onLongClick(this),在up事件之后调用,默认触发时间是500毫秒.
    private static final int DEFAULT_LONG_PRESS_TIMEOUT = 500;

=========================================================

在下一篇我将写一篇关于Android的Touch事件流程,敬请期待.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值