在Android中查找包含视图的窗口

27

我无法找到一种方法来获取包含任意 View v 的 Window 引用。我发现 getWindowToken,但我不知道如何使用它?有人知道吗?

此外,有人知道为什么它返回一个 IBinder 而不是一个 Window 吗?

2个回答

19

嗯...由于所有视图都有一个创建它们的活动(Context)的引用,因此您可以使用该Context来获取窗口的引用。让我向您展示我几分钟前编写的这个示例:

// main activity
import android.app.Activity;
import android.os.Bundle;
public class GetWindow extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MyView view = new MyView(this);
        view.changeSomethingInWindow(); // keep an eye on this method
        setContentView(view);
    }
}

然后,在您的视图中可以这样做:

// your view :D
import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

public class MyView extends View{
    public MyView(Context context) {
        super(context);
    }

    @Nullable
    private Activity getActivity() {
        if (context == null) return null;
        if (context instanceof Activity) return (Activity) context;
        if (context instanceof ContextWrapper) return getActivity(((ContextWrapper)context).getBaseContext());
        return null;
    }
 
    public void changeSomethingInWindow(){
        // get a reference of the activity
        Activity parent = getActivity();
        if(parent == null) return;
        // using the activity, get Window reference
        Window window = parent.getWindow();
        // using the reference of the window, do whatever you want :D
        window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }
}

在这种情况下,我将窗口显示模式更改为全屏。希望这可以帮助你。如果你遇到问题,请告诉我。


2
谢谢你的回答。使用getWindow并将其转换为Activity是个好主意。我不知道为什么会返回IBinder而不是Window,你有什么想法吗? - Casebash
1
你好,Casidiablo,你的代码出了问题。这只可能适用于您在自己的代码中创建视图的方式,您使用的自定义构造函数中的上下文是一个活动。我尝试了ListAdapter中的Item的getContext方法,在这种情况下,我得到的是Context而不是Activity。Activity是Context的子类,这意味着您可以获得无法转换为Activity的Context对象。我的测试代码最终导致了ClassCastException。 - Janusz
99
误导的回答。并非所有视图都用于Activity!有些视图在PopupMenu、Dialog或AppWidgetProvider中使用。你会得到类转换异常或错误的窗口。Dialog有自己的窗口。请修改您的回答。 - Pointer Null
那么如何解决这个问题呢?我也遇到了同样的情况。ClassCastException。 - JP Wile
但是一个活动可以有几个窗口吗? - zeus
显示剩余5条评论

1

我知道这是一个老问题,但在搜索谷歌时仍然会重定向到此处,由于上面的答案不完全有效,这就是我所做的更改视图内部窗口标志的方法。(上面的代码基本上做了同样的事情,但它假设所有视图都附加到活动中。)

它不会获取实际的 Window 实例,而是返回属性,这允许更新标志,或者在此时窗口具有的任何东西。

装饰视图或附加到窗口的顶部视图应该具有 WindowManager.LayoutParams 的实例,并且您应该能够设置所需的标志,因为参数具有 WindowManager.LayoutParams.flags 整数值。以下是获取窗口参数的方法。

private WindowManager.LayoutParams tryGetWindowParams()
{
    View view = this;
    if (view.getLayoutParams() instanceof WindowManager.LayoutParams)
        return (WindowManager.LayoutParams) view.getLayoutParams();
    while (view.getParent() instanceof View)
    {
        view = (View) view.getParent();
        if (view.getLayoutParams() instanceof WindowManager.LayoutParams)
            return (WindowManager.LayoutParams) view.getLayoutParams();
    }
    return null;
}

之后,你应该能够只需执行以下操作(示例将使用FLAG_NOT_TOUCHABLE标志,但可以根据需要使用任何其他窗口标志)。

private boolean setWindowNotTouchable()
{
    WindowManager.LayoutParams windowParams = tryGetWindowParams();
    if (windowParams != null)
    {
        if ((windowParams.flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) == 0)
        {
            windowParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
            requestLayout();
        }
        return true;
    }
    return false;
}

private boolean setWindowTouchable()
{
    WindowManager.LayoutParams windowParams = tryGetWindowParams();
    if (windowParams != null)
    {
        if ((windowParams.flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
        {
            windowParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
            requestLayout();
        }
        return true;
    }
    return false;
}

不要忘记调用View.requestLayout(),因为窗口参数需要更新。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接