ExpandableNotificationRow
# onFinishInflate
ExpandableNotificationRow
在方法 onFinishInflate
中提到它的布局。
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mPublicLayout = findViewById(R.id.expandedPublic);
mPrivateLayout = findViewById(R.id.expanded);
mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
for (NotificationContentView l : mLayouts) {
l.setExpandClickListener(mExpandClickListener);
l.setContainingNotification(this);
}
mGutsStub = findViewById(R.id.notification_guts_stub);
mGutsStub.setOnInflateListener((stub, inflated) -> {
mGuts = (NotificationGuts) inflated;
mGuts.setClipTopAmount(getClipTopAmount());
mGuts.setActualHeight(getActualHeight());
mGutsStub = null;
});
mChildrenContainerStub = findViewById(R.id.child_container_stub);
mChildrenContainerStub.setOnInflateListener((stub, inflated) -> {
mChildrenContainer = (NotificationChildrenContainer) inflated;
mChildrenContainer.setIsLowPriority(mIsLowPriority);
mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
mChildrenContainer.onNotificationUpdated();
mTranslateableViews.add(mChildrenContainer);
});
// Add the views that we translate to reveal the menu
mTranslateableViews = new ArrayList<>();
for (int i = 0; i < getChildCount(); i++) {
mTranslateableViews.add(getChildAt(i));
}
// Remove views that don't translate
mTranslateableViews.remove(mChildrenContainerStub);
mTranslateableViews.remove(mGutsStub);
}
ExpandableNotificationRow
类的 onFinishInflate
方法负责完成视图的填充过程。该方法在 XML 布局被填充成实际的视图对象之后被调用,确保所有必要的视图都被正确设置。
在提供的代码片段中,执行了几个关键步骤:
-
mPublicLayout
和mPrivateLayout
通过查找相应 ID(R.id.expandedPublic
和R.id.expanded
)的视图来初始化。这些是NotificationContentView
的实例,用于显示通知的公共(为了隐私而编辑过的内容)或私有(完整内容)形式。 -
对
mLayouts
中的每个布局,调用setExpandClickListener
和setContainingNotification
来设置点击监听器,并将布局与这个ExpandableNotificationRow
关联。 -
mGutsStub
通过其视图 ID 查找,并设置了OnInflateListener
。当mGutsStub
被填充时,它变成了mGuts
,这是一个用于显示通知附加详情或操作(如延迟或屏蔽选项)的NotificationGuts
视图。 -
类似地,
mChildrenContainerStub
被查找并设置了OnInflateListener
。在填充之后,它变成了mChildrenContainer
,这是一个NotificationChildrenContainer
,如果当前通知是分组通知中的摘要,则包含子通知。 -
mTranslateableViews
被初始化并填充了ExpandableNotificationRow
的所有子视图。某些视图如mChildrenContainerStub
和mGutsStub
被从列表中移除,因为它们不参与某些平移动画(如显示通知菜单时)。
onFinishInflate
方法结束时,ExpandableNotificationRow
已经设置好了所有内部视图,并准备好显示通知内容,如果它是一个摘要通知,还包括任何子通知。Guts 和 children container 视图作为存根开始,并在需要时被填充,这可以通过延迟加载更复杂的视图直到实际需要它们来提高性能。
ExpandableNotificationRow
的布局文件是 R.layout.status_bar_notification_row
,这个视图用于展示一个可扩展的通知行。ExpandableNotificationRow
继承自FrameLayout
,因此它可以包含多个子视图。布局中的元素定义了通知行的不同部分,包括背景、内容视图(包括公共和私有内容),以及其他的一些视图和视图存根(ViewStub
)。
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2014, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- extends FrameLayout -->
<com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/expandableNotificationRow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:clickable="true"
>
<!-- Menu displayed behind notification added here programmatically -->
<com.android.systemui.statusbar.notification.row.NotificationBackgroundView
android:id="@+id/backgroundNormal"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.android.systemui.statusbar.notification.row.NotificationBackgroundView
android:id="@+id/backgroundDimmed"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.android.systemui.statusbar.notification.row.NotificationContentView
android:id="@+id/expanded"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.android.systemui.statusbar.notification.row.NotificationContentView
android:id="@+id/expandedPublic"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/veto"
android:layout_width="48dp"
android:layout_height="0dp"
android:gravity="end"
android:layout_marginEnd="-80dp"
android:background="@null"
android:paddingEnd="8dp"
android:paddingStart="8dp"
/>
<ViewStub
android:layout="@layout/notification_children_container"
android:id="@+id/child_container_stub"
android:inflatedId="@+id/notification_children_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<ViewStub
android:layout="@layout/notification_guts"
android:id="@+id/notification_guts_stub"
android:inflatedId="@+id/notification_guts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<com.android.systemui.statusbar.notification.FakeShadowView
android:id="@+id/fake_shadow"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.android.systemui.statusbar.notification.row.ExpandableNotificationRow>
下面是对这个布局文件中各个主要组件的解释:
-
ExpandableNotificationRow:
- 这是自定义的根视图,扩展自
FrameLayout
,表示一个可以扩展的通知单元。 -
android:id
:视图的ID,可以在代码中用来引用该视图。 -
android:layout_width
和android:layout_height
:定义视图的宽度和高度。这里宽度是填满父视图(match_parent
),高度是包裹内容(wrap_content
)。 -
android:focusable
和android:clickable
:这两个属性设置视图可以获取焦点和接受点击事件。
- 这是自定义的根视图,扩展自
-
NotificationBackgroundView:
- 两个背景视图(
backgroundNormal
和backgroundDimmed
)被用于显示通知的背景,一个用于正常状态,一个用于昏暗状态。
- 两个背景视图(
-
NotificationContentView:
- 两个
NotificationContentView
分别代表公共和私有的通知内容。 -
android:id="@+id/expanded"
:私有(完整)内容的视图。 -
android:id="@+id/expandedPublic"
:公共(简略)内容的视图。
- 两个
-
Button (id: @+id/veto) :
- 一个按钮视图,可能用于提供通知的某种快速操作,例如删除通知。
- 使用负的
layout_marginEnd
,这可能是为了使按钮在视觉上超出其自然位置,创建一种特殊的布局效果。
-
ViewStub (id: @+id/child_container_stub) :
- 一个
ViewStub
用于延迟加载notification_children_container
布局。这通常用于节省资源,因为ViewStub
只有在需要时才会被填充成真正的视图。 - 该布局用于显示分组通知的子通知。
- 一个
-
ViewStub (id: @+id/notification_guts_stub) :
- 另一个
ViewStub
用于延迟加载notification_guts
布局。这个布局包含了通知的额外操作,例如设置或者是延迟提醒。
- 另一个
-
FakeShadowView (id: @+id/fake_shadow) :
- 一个用于显示阴影效果的视图,可能用于创建提升效果,使通知看起来像是悬浮在上面。
注意:真实的动态视图(例如通知的内容或操作按钮)通常是在代码中动态添加的,而不是直接在XML中硬编码的。因此,ViewStub
和动态添加的视图允许开发者根据需要延迟视图的创建和配置。
ExpandableNotificationRow
# isTopLevelChild
ExpandableNotificationRow
类的 isTopLevelChild
方法体现了类NotificationStackScrollLayout
是它的父布局。
public boolean isTopLevelChild() {
return getParent() instanceof NotificationStackScrollLayout;
}
ExpandableNotificationRow
类是用来展示 Android 系统中的通知,其中包括可以折叠和展开的分组通知。当一个通知是分组通知的头部(即摘要),它可以包含多个子通知。这里有几个关键点说明了 ExpandableNotificationRow
如何管理和展示其子通知:
-
子通知容器 (
NotificationChildrenContainer
) :ExpandableNotificationRow
通过NotificationChildrenContainer
管理其子通知。这个容器是一个自定义视图,负责布局和展示所包含的所有子通知。NotificationChildrenContainer
将在ViewStub
被实例化(inflate)时创建,并且只有当通知确实有子通知时才会被加载。 -
延迟加载 (
ViewStub
) :ExpandableNotificationRow
布局中包含一个ViewStub
(ID为@+id/child_container_stub
),它被用来按需加载包含子通知的容器。ViewStub
是一种轻量级的占位视图,直到需要展示子通知时才会被实例化成NotificationChildrenContainer
。 -
子通知展示: 当
ExpandableNotificationRow
确定为一个分组通知的头部时,它会将子通知添加到NotificationChildrenContainer
中。子通知每个都是ExpandableNotificationRow
的实例,它们会被垂直堆叠显示。 -
展开和折叠: 分组通知可以通过用户交互(点击、滑动等)或编程方式(如响应其他事件)来展开或折叠。
ExpandableNotificationRow
控制其NotificationChildrenContainer
的展开状态,当用户展开分组时,子通知将会显示出来;当折叠分组时,这些子通知会被隐藏,只显示摘要。 -
用户交互:
ExpandableNotificationRow
还包含逻辑来处理用户的交互,例如点击通知来展开或折叠分组。这通常通过设置点击监听器来实现,当用户点击时,会切换分组的展开状态。 -
通知更新: 当通知行更新时,(例如,当新的子通知到来或现有的子通知被移除时),
ExpandableNotificationRow
会更新其NotificationChildrenContainer
,添加或删除子通知元素,并重新布局以反映最新的子通知列表。
ExpandableNotificationRow
和 NotificationChildrenContainer
共同工作,确保分组通知的子通知可以被适当地管理和展示,同时也提供了丰富的用户交互以及对展开和折叠状态的响应。
网友评论