前言
今天的工作仍然在思考自定义view,因为需要调服务器接口,而这需要一些参数去其他地方拿,不在我调自定义view的页面,所以我希望能封装好这个自定义view,对外只要开放相应监听接口即可,所以第一步我很快就完成了view的触摸事件监听,使我的控件能满足触摸的反应需求,在对竖屏和横屏适配后,我陷入了如何封装的思考中。
这是关于对控件移动边缘限定的宽高获取:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 获取宽-测量规则的模式和大小 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); // 获取高-测量规则的模式和大小 heightMode = MeasureSpec.getMode(heightMeasureSpec); heightSize = MeasureSpec.getSize(heightMeasureSpec); //获取xml里面设置的宽高的像素值 XLog.i(TAG + " widthSize= " + widthSize + ",heightSize = " + heightSize); }
此外,我发现可以在上面这个测量方法中初始化一些从外部传入的全局变量
而在onDraw()方法复写中,只要getWiidth() 和 getHeight 即可轻松获取高和宽。
正篇
但我还没想多久,就发现自己手中的自定义view有问题,竖屏时因为固定在Dialog中的所以没有发现,而横屏就出现了问题,有时候控件在view的边缘按下时会出现卡死在边缘无法回到我预设的起始点,于是赶快看了代码:
setOnTouchListener(new OnTouchListener() { //设置触控监听 @Override public boolean onTouch(View v, MotionEvent ev) { //因为本人控件为圆形的,故这样写 final float xx = ev.getX() - widthSize * 0.5, yy = ev.getY() - heightSize * 0.5; if (ev.getAction() == MotionEvent.ACTION_DOWN) { m.down(xx, yy);//按下时的操作 // m.move(xx, yy); } m.move(xx, yy);//移动时的操作 if (ev.getAction() == MotionEvent.ACTION_UP) { m.up();//松开时的操作 } return true;//不要返回false } });
请教完前辈发现,有时候安卓在布局边缘处的触控事件是不会触发为UP操作的,应该如下:
if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_OUTSIDE) { m.up();//松开时的操作 }
这里解释一下,ACTION_CANCEL就是对应手势被取消了,而ACTION_OUTSIDE则是表明是触碰超出了正常的 UI 边界,而通过日志发现我的ev.getAction()返回的是3,即ACTION_CANCEL,那为什么会出现这种情况呢?这里有一个问答就说明了这个情况发生的原因:
大意就是有人问安卓中出现ACTION_CANCEL是什么原因,下面大佬就回答道,当父级接管运动时,就会发生ACTION_CANCEL,例如,当用户在列表视图中拖动的动作过大,甚至让它即将开始滚动,而不是让你能够按下这其中的按钮。
也就是说我对自定义view的触控过头了,导致了取消事件发生从而出现这个Up动作监听不到的问题。
总结
其实出现这个问题还是我源码阅读不够多,不能想到对策与方法,不过贵在积累,明理而笃行。