关于浮在界面上的可拖动窗口(控件),现在知道的有三种方案。
1.FloatView
FloatView是指在所有窗口(包括其他Activity,其他程序,桌面)上面的浮动窗口,一些浮动菜单,工具栏,流量监控界面等,github上找了几个例子,似乎需要权限。虽然有些方案说是不需要权限,还没弄明白。
暂时不需要。
2.Dialog
这个就是弹出对话框了,拖动也能做,但是问题是它是和原来的界面分离了,没关闭的情况下无法操作原来的界面。
3.DragView
这个其实就是我需要的,只要把一个控件浮动到另一个控件的上面(具体来说是把webrtc的SurfaceViewRenderer浮动到unity界面的前面,显示摄像头监控视频,并且可以拖动)。
基本原型很简单,创建一个新的类,继承某个控件类,修改一下onTouchEvent就行,而且我不是拖动到另一个控件里面,只是需要拖动而已,不需要里面的第二步。
不过,需要继承,耦合度高,而且发现,只有在被拖动控件在左上角才有效,在其他地方,如多个Button的后面几个,会有偏移。经测试发现需要把控件的起始位置记录下来。
另外改成通过Listener方式来解耦。
总之最后写了个Dragger类
package com.shencode.cww.drag;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
public class Dragger {
private View view;
private ViewGroup parent;
private float moveX;
private float moveY;
private float localX;
private float localY;
private float localZ;
private static float maxLocalZ=-1;
private boolean isFirst=true;
public Dragger(View view,boolean onlyDrag){
this.view=view;
this.onlyDrag=onlyDrag;
ViewTreeObserver vto=view.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// showXYZ("Dragger");
initXYZ();
}
});
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return onTouchEvent(v,event);
}
});
ViewParent p=view.getParent();
if(p instanceof ViewGroup){
parent=(ViewGroup)p;
}
//parent.getch
}
private void initXYZ() {
if (isFirst) {
localX = view.getX();
localY = view.getY();
localZ = view.getZ();
isFirst = false;
Log.d("initXYZ", String.format("%s (%s,%s,%s)(%s,%s)", view, view.getX(), view.getY(), view.getZ(), view.getTranslationX(), view.getTranslationY()));
getMaxZ();
}
}
private void getMaxZ(){
if(maxLocalZ<0){
ViewParent p=view.getParent();
if(p instanceof ViewGroup){
parent=(ViewGroup)p;
}
if (parent != null) {
for (int i = 0; i < parent.getChildCount(); i++) {
View c = parent.getChildAt(i);
float z = c.getZ();
if (z > maxLocalZ) {
maxLocalZ = z;
Log.d("getMaxZ", "maxLocalZ2:" + maxLocalZ);
}
}
}
}
}
//fasle:可以进行控件的固有操作,但是webrtc的SurfaceViewRenderer不能拖动了。
//true:只能拖动,button的click事件,checkbox的check事件,editoview的输入功能都没有
private boolean onlyDrag=true;
private boolean onTouchEvent(View v,MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
moveX = event.getX()+localX;
moveY = event.getY()+localY;
//view.bringToFront();//这个会改变在LinearLayout里面的位置,不行
v.setZ(maxLocalZ+0.1f);//Z设置太高的话会有阴影
showXYZ("onTouchEvent");
break;
case MotionEvent.ACTION_MOVE:
v.setTranslationX(v.getX() + (event.getX() - moveX));
v.setTranslationY(v.getY() + (event.getY() - moveY));
break;
case MotionEvent.ACTION_UP:
v.setZ(localZ);
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return onlyDrag;
//fasle:可以进行控件的固有操作,但是webrtc的SurfaceViewRenderer不能拖动了。
//true:只能拖动,button的click事件,checkbox的check事件,editoview的输入功能都没有
}
private void showXYZ(String tag){
Log.d(tag,String.format("%s (%s,%s),(%s,%s,%s),(%s,%s)",view,moveX,moveY,view.getX(),view.getY(),view.getZ(),view.getTranslationX(),view.getTranslationY()));
}
public static void setDragger(View view,boolean onlyDrag){
Dragger dragger=new Dragger(view,onlyDrag);
}
}
使用上可以新建控件,也可以单独使用。
public class DragButton extends AppCompatButton {
Dragger dragger=new Dragger(this);
public DragButton(Context context) {
super(context);
}
public DragButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DragButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
Button btnDragTestButton1=findViewById(R.id.btnDragTestButton1);
Dragger dragger=new Dragger(btnDragTestButton1);
findViewById(R.id.btnDragButton1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("DragTestActivity","btnDragTestButton1 onClick:"+v);
}
});
经过测试,这种方式,什么控件都能拖动,而且也能正常使用(onTouchEvent返回true的话可能是拦截了后续的操作了,控件的交互功能就没有了)。
----------------------------------------------------
另外找到一个ViewDragHelper,参考:Android中神奇的ViewDragHelper
按着创建了一个DragLinearLayout,测试发现DragLinearLayout里面的View和TextView可以拖动,但是里面的Button,CheckBox,EditView等有具体交互功能的控件都不能拖动。
后面有空再研究ViewDragHelper吧,先用我写的Dragger了。
-------------------------------------------------------
对控件的长宽进行调整,或者布局发生变化。
private void setViewSize(View v, int w, int h){
ViewGroup.LayoutParams lp=v.getLayoutParams();
lp.width=w;
lp.height=h;
v.setLayoutParams(lp);
}
可能会导致物体的初始位置发生变化,需要重新设置一下localXYZ。
public void reInit(){
isFirst=true;
initXYZ();
}
另外加了个reset,恢复初始位置
public void reset(){
view.setX(localX);
view.setY(localY);
view.setZ(localZ);
}
--------------------------------------------------------------------------------------------
后来了解到还有其他方式,参考:5分钟搞定PopUpWindow,Android Popupwindow 拖动
弹窗有很多种实现方式,例如:
Dialog
DialogFragment
Fragment
PopUpWindow
ListPopUpWindow
PopUpWindow更似乎功能需求。
具体看下一篇吧《UnityAndroid(4) Unity上显示窗口》