我尝试实现一个在屏幕上拖动view, 让view移动的功能.
我是这样做得:
但是出现了下面很奇怪的问题: (见录制的屏幕)
似乎按钮只会在某个小窗口内部分是visible的, 其他的话就被盖住.
可是自己设置了framelayout的大小都是match_parent, 可能framelayout给每个fragment分配的空间太小了?
可是我尝试改变了view的maxwidth也不行.....
自己不太知道该如何解决, 希望大家帮忙! 多谢!
怪我咯2017-04-17 13:08:26
監聽TouchEvent跟你想的差不多..我通常這樣操作.
1.Down事件發生後,獲得需要移動的View的cache bitmap
Bitmap bitmap = targetView.getDrawingCache()
或者调用targetView的draw方法绘制在自己创建的canvas上来得到当前快照
2.新建一個ImageView,把快照丟進去
3.使用WindowMananger在螢幕上加上一個圖層,把ImageView丟到你的按鈕原來的位置上,把你原來那個按鈕隱藏
4.然後剩下的和你的思路一致,你只要移動WindowManager裡的ImageView就好了...這個圖層是全屏...不受限制
5.ACTION_UP以後...把WindowMananger的內容刪除,把你的Button移到Action_up發生的位置.
不推薦的你 做法是因為 直接修改View的位置...會引起整個View tree的重佈局...非常影響性能..
而且你要改的不是setx sety....是LayoutParamters裡的xy
View的setx sety是繪圖的起始位置...相當於setTranslationX/Y view根本沒動...
補充:
1.關於WindowMananger方案請參考這段程式碼:
wm = (WindowManager) getApplicationContext().getSystemService("window");
wmParams = new WindowManager.LayoutParams();
wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
wmParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
wmParams.gravity = Gravity.LEFT | Gravity.TOP;
wmParams.x = 0;
wmParams.y = 0;
wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
wmParams.format = PixelFormat.RGBA_8888;
wm.addView(view, wmParams);
view.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
x = event.getRawX();
y = event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchStartX = event.getX();
mTouchStartY = event.getY() + view.getHeight() / 2;
break;
case MotionEvent.ACTION_MOVE:
updateViewPosition();
break;
case MotionEvent.ACTION_UP:
updateViewPosition();
mTouchStartX = mTouchStartY = 0;
break;
}
return true;
}
});
--
private void updateViewPosition() {
wmParams.x = (int) (x - mTouchStartX);
wmParams.y = (int) (y - mTouchStartY);
wm.updateViewLayout(view, wmParams);
}
2.ViewGroup其實有個ClipChildren的私有欄位控制當childview超出子佈局的時候是否要繪製.
應用的範例: https://github.com/dkmeteor/CircleList
核心程式碼:
public void changeGroupFlag(Object obj) throws Exception
{
Field[] f = obj.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredFields(); // 获得成员映射数组
for (Field tem : f)
{
if (tem.getName().equals("mGroupFlags")) {
tem.setAccessible(true);
Integer mGroupFlags = (Integer)tem.get(obj);
int newGroupFlags = mGroupFlags & 0xfffff8;
tem.set(obj, newGroupFlags);
}
}
}
注意這個屬性是私有欄位,該Demo中使用反射修改了mGroupFlags欄位...不建议使用
.
3.如何在setLayoutParams裡面像setX, setY一樣設定位置
那取決於LayoutParams的種類,LayoutParams又取決於該View的父佈局
LayoutParams有很多很多種
例如 ViewGroup.LayoutParams RelativeLayout.LayoutParams WindowManager.LayoutParams 等很多種,每一種支援的屬性不一樣.
例如AbsoluteLayout.LayoutParams 就有 x y屬性可以直接設定位置
但是 LayoutParams.LayoutParams 就只能設定margin
4.你對View繪製流程的理解有偏差.
這部分有點複雜......View的繪製是由自身完成的...View不會繪製超出自己bounds/rect區域以外的部分....我講不大清楚...
你可以參考Android 5.0 View原始碼 14959行~14977行(在View.draw 中間那一段) 關於clipRect部分的邏輯
我在上面回答2裡 CircleList 裡使用方法 實際上最終就是透過反射修改了 ViewGroup.mGroupFlags的值,該值在繪圖流程中會影響子View繪製時Clip這部分的邏輯,
PS.試著寫了一下..發現我是說不清楚這個問題了....