思路一:
1>上下两个LinearLayout,分别addView对应的itemView
2>new一个二维数组,分别记录热区范围,选项最终要落下的位置范围
3>拖动控件的时候可以通过不停的绘制,来达到移动的效果
4>判断是否在热区范围,确定最终的位置
优点:
1.上手比较容易,获取到第一个itemView距离左边的距离,每个itemView的leftTop与rightBottom排排算就
2.由于是在一个界面不停绘制,不用考虑选项控件无法拖出去的问题
缺点:
1.数组写死的,代码量恶心,只能改动配置在dimens里面的字段
2.可读性差
思路二:
1.自定义ViewGroup,题目与选项作为子View放在父布局中,通过List记录加进来的每个view
2.无法将控件拖动出去,采用WindowManager,改变x,y,updateViewLayout来改变控件的位置
优缺点就不赘述了,这个方案我实践过,通过WindowManager来使view移动,总感觉不是很合适,并不是要做真正悬浮的弹窗。。
思路三:
动态计算热区范围,舍弃数组,舍弃绘制(位置不好控制)
问题1:怎么动态计算
view中提供了对应的方法:
getLocationOnScreen----相对于整个屏幕view的绝对坐标,顶端算起
getLocationInWindow----相对于当前窗口view的绝对坐标
但是调用这两个方法需要时机,需要在view绘制完成的时候调用
getViewTreeObserver().addOnGlobalLayoutListener(布局完成时候调用,每次布局改变时候调用),注意点是:可能会被触发多次,所以需要获取到相应数据后,注销掉
通过getLocationOnScreen可以获取到view对应leftTop的x,y数值 ,我们获取view对应的leftToprightBottom就可以计算出来。
红色布局为我获得的热区范围:显然不对!
忽略了getLocationOnScreen是从顶端算起的,刚开始想当然的减去了状态栏的高度,发现热区范围还是不对,检查代码发现自己继承的activity是AppCompatActivity(当然界面体现的更直观一点)应该还应减去actionbar的高度。
网上搜的对该方法的解释,有一定的漏洞,记住是从顶端算起就可以了,不要想当然的只减去通知栏的高度
这样热区范围大致定下来了。。。
但是,当给父布局设置android:gravity="center"后,热区范围又乱了。。可能这时候也意识到了,通过getLocationOnScreen方法获取到的x也应该减去该view距离左边的距离。。。
其他范围的热区同理
问题2:选项作为独立的自定义View,是LinearLayout addView进去的,所以选项可以移动的范围只有下方的这片区域,无法整体移动
在拖动选项时,父布局可以add一个新的拖动的view,原来的view invisiable
疑问:为什么不直接移动之前的,因为布局会乱掉
问题3:拖动的控件与自己手势不符
原先代码:开始代码:move-->setX(getRawX()) setY(getRawY())
忽略了需要减去偏移量。。
后来:move-->setX(getRawX()-x轴) setY(getRawY()-y轴)
基础知识普及:
疑问:为什么不用getX
根据图示:getRawX-偏移量===getLeft()+getX()
但是在实际拖动的时候,会发现getLeft获取到的始终是初始的默认值
基础知识普及:
getLeft(): 是子View距离父View左边的距离, 这个值不会随着View的属性(transitionX和X)的改变而改变。View在layout的时候,会调用setFrame()函数来改变left的值。也可以直接调用setLeft()来改变left值,但是调用setLeft方法之后,View的宽度也会改变。因为View的大小是right - left之间的块。(好像api并不提倡直接改变调用set方法),同时调用setLeft()和setRight()方法会改变View的大小。
getTranslationX():TranslationX 是view 相对于第一初始化时候(View 相对于left的位移),自己的位置的偏移量,向右为正,向左为负,第一次初始化时候为0。可以用setTranslationX()方法,或者动画来改变这个偏移量,而TranslationX的值得改变,不会导致getLeft()的值得改变。属性动画改变的是x和translationX的值,没有改变left的值。
getX() = getLeft() + getTranslationX(), 注意setX其实是设置setTranslationX()
所以答案是:用不了
问题4:选项动画漂移
1.ObjectAnimator
需要传入(startPosition,endPositoin)
2.TranslateAnimation
只需要知道endPositoin
注意:都是差值,因为是拖动,所以startPositon差值为0
fromXDelta:这个参数表示动画开始的点离当前View X坐标上的差值;
toXDelta, 这个参数表示动画结束的点离当前View X坐标上的差值;
fromYDelta, 这个参数表示动画开始的点离当前View Y坐标上的差值;
toYDelta)这个参数表示动画开始的点离当前View Y坐标上的差值;
代码地址:GitHub - guohaiping521/QuestionView