概述:
最近再看Android的小窗模式,接到需求,窗口的标题栏上有“全屏”、“关闭”两个按钮,需要能使用遥控器聚焦(默认是无法获焦的),并且能遥控触发相关的点击事件,特此记录下。
具体的小窗模式的介绍、开启、使用等等资料大家就自行查阅了,我这里贴出一篇详细的介绍文章,强烈建议感兴趣的小伙伴看看。
参看文章:
找到小窗模式的标题栏View:
根据查阅的资料,Android13中,小窗的创建主要就是DecorView中会根据判断,是否创建标题栏DecorCaptionView。因此就要去Frameworks源码中找到相关的类,并查看其相关的Layout布局。
DecorView源码位置:
frameworks/base/core/java/com/android/internal/policy/DecorView.java
DecorCaptionView源码位置:
frameworks/base/core/java/com/android/internal/widget/DecorCaptionView.java
经过查找,再DecorView中找到了,如何创建DecorCaptionView:
private DecorCaptionView inflateDecorCaptionView(LayoutInflater inflater) {
final Context context = getContext();
// We make a copy of the inflater, so it has the right context associated with it.
inflater = inflater.from(context);
final DecorCaptionView view = (DecorCaptionView) inflater.inflate(R.layout.decor_caption,
null);
setDecorCaptionShade(view);
return view;
}
因此我们就看R.layout.decor_caption布局文件
<com.android.internal.widget.DecorCaptionView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants" >
<LinearLayout
android:id="@+id/caption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:background="@drawable/decor_caption_title"
android:focusable="false"
android:descendantFocusability="afterDescendants" >
<Button
android:id="@+id/maximize_window"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_margin="5dp"
android:padding="4dp"
...
...
/>
...
...
/>
打开获焦模式:
根据R.layout.decor_caption布局文件,我们可以看到DecorCaptionView的子布局LinearLayout的获焦模式是:
android:descendantFocusability="blocksDescendants"
这就导致该布局的子布局无法获取焦点。
因此我们需要把blocksDescendants换成beforeDescendants:子布局优先获得焦点。同时把两个button的 android:focusable="true"
添加上,重新编译系统,刷机后就能发现,小窗模式的全屏、关闭按钮能获得焦点了。
添加焦点事件:
按照上面的步骤,就能使得全屏、关闭两个按钮触发聚焦,但是聚焦后的确认(点击)事件无法触发,这是因为,小窗模式的标题栏为了避免和窗口内部的View有触摸穿透问题,做相关的拦截(如果触摸事件发生在标题栏,则要拦截手势事件),两个button使用的是touch事件来触发相关的调用,具体看DecorCaptionView代码内部的
onInterceptTouchEvent()方法和onTouchEvent()方法以及相关的touch事件。
经过查找,发现“全屏按钮”触发的调用是:
toggleFreeformWindowingMode()
“关闭按钮”触发的调用是:
mOwner.dispatchOnWindowDismissed( true /*finishTask*/, false /*suppressWindowTransition*/);
因此我们就要给全屏按钮和关闭按钮添加遥控确认的点击事件:
mMaximize = findViewById(R.id.maximize_window);
mMaximize.setOnClickListener(v -> {
toggleFreeformWindowingMode();
});
mClose = findViewById(R.id.close_window);
mClose.setOnClickListener(v -> {
mOwner.dispatchOnWindowDismissed(
true /*finishTask*/, false /*suppressWindowTransition*/);
});
至此小窗模式下,右上角的“全屏”、“关闭”按钮的遥控事件就顺利的解决了。