在 Android 开发中,Material Design 是一种非常流行的 UI 设计风格。AppBarLayout 是 Material Design 中常用的控件之一,它可以实现顶部导航栏、可折叠的标题栏等功能。然而,使用 AppBarLayout 经常会遇到一个问题:当 AppBarLayout 中的内容发生变化时,它的高度也会发生变化,这会导致布局出现问题。本文将介绍如何解决这个问题。
问题分析
首先,我们来看一个简单的例子。假设我们有一个包含一个 TextView 的布局文件,如下所示:
---------------------------------------------------- ----------------------------------- ------------------------------------- ------------------------------------------------ ------------------------- ----------------------------------- ------------------------------------- ----------------------------------------------------------- ----------------------------------- ------------------------------------ -------------------------------- ---------------------------------- ------------------------- ----------------------------------- ------------------------------------------- ----------------------------- -- ------------------------------------------------------------- -------------------------------------------------- --------- --------------------------- ----------------------------------- ------------------------------------ ------------------- ------- -- ------------------------------------------------------
这个布局文件包含一个 CoordinatorLayout,一个 AppBarLayout 和一个 TextView。AppBarLayout 中包含一个 CollapsingToolbarLayout 和一个 Toolbar,用于实现可折叠的标题栏。TextView 用于显示一段文本。
现在,我们想在 TextView 中显示一个长文本,例如一篇文章。我们可以通过在 TextView 中设置一个长文本来实现:
-------- -------- - ----------------------------- ------ -------- - ------ ----- ----- --- ----- ----------- ---------- ----- --- -- ----- --- ----- --------- -------- ----- -- ---- -- ---- --------- ------ ---- ------- --- - -------- ---------- ------ ----- ------- ----- -- -------- ---- ----- -- ----- --- --- ---- -- ----- ------------ ---------- --- -------- ---- ----- ------- -------- ---- ------ ------- ----- - -------- ---- ----- --- ------ ----------- -------- --- ---- ------- ------- -- ---- ---- -------- -------- ------ --- ---------- ------ --- ---- -------- --------- ----- ---- ------------ ------- -- -------- ----- -- -- ------- --- ------- ----- -- ----------- -------- ----- ----- -------- ----- ----- ------ ---- --- - ---- ----- ------ ------ --------- -- ----- ---- ------------ ------- ----- ------- ---- --------- ----- -- ----- -------- -------- ----- --- -------- ------- ------- ---- --------- ----- ------- ----- -- ----- -------- --- -------- ----- -------- --- --- ------ ------- ---------------------------
然而,当我们运行应用程序时,会发现 TextView 的高度发生了变化,导致布局出现问题。具体来说,AppBarLayout 的高度变得很大,导致整个布局向下移动,如下图所示:
这个问题的原因是,当 AppBarLayout 中的内容发生变化时,它的高度也会发生变化。具体来说,AppBarLayout 的高度等于它内部所有可滚动的子视图的高度之和。在上面的例子中,TextView 是可滚动的,因此它的高度被计算在内。
解决方案
为了解决这个问题,我们需要让 AppBarLayout 的高度不受内部可滚动子视图的影响。具体来说,我们可以使用一个自定义的 Behavior 来覆盖 AppBarLayout 的默认行为。Behavior 是一个与 View 相关联的类,它控制 View 在 CoordinatorLayout 中的交互。AppBarLayout 的默认 Behavior 叫做 AppBarLayout.Behavior,我们可以继承它并覆盖其中的一些方法来实现我们的需求。
下面是一个自定义的 Behavior,它的作用是在 AppBarLayout 中包含可滚动子视图时,将它们的高度从 AppBarLayout 的高度中排除:
------ ----- ------------------------ ------- --------------------- - ------ -------------------------- - -------- - ------ -------------------------------- -------- ------------ ------ - -------------- ------- - --------- ------ ------- -------------------------------- ------- ------------ ------ --- ----------------------- --- ---------- --- ------------------------ --- ----------- - --- ----------- - -- --- ---- - - -- - - ---------------------- ---- - ---- ---- - -------------------- -- ----- ---------- --------------------- - --- ----------------- - ----------------------------------- ------------------------------ --- ---------------- - --------------------------------------------------- -------------------------- ------------------------------ ------------------- ----------- -- ------------------------- - - --- ----------------- - --------------------------------------------------- - ------------ -------------------------- ---------------------------- ------ ----------------------- ---------- ------------------ ------------ ------ ----- - -
这个 Behavior 继承自 AppBarLayout.Behavior,它覆盖了 onMeasureChild 方法。onMeasureChild 方法的作用是测量子视图的尺寸,并返回它们的测量结果。在默认的实现中,AppBarLayout.Behavior 测量子视图的尺寸时,会将所有可滚动子视图的高度加起来,作为 AppBarLayout 的高度。在我们的自定义 Behavior 中,我们将排除所有可滚动子视图的高度,只将非可滚动子视图的高度加起来,作为 AppBarLayout 的高度。
具体来说,我们遍历 AppBarLayout 中的所有子视图,如果子视图是可滚动的(即实现了 NestedScrollingChild 接口),则测量它的尺寸,并将它的高度加起来。最后,我们计算出排除可滚动子视图后的高度,将它作为 AppBarLayout 的高度,并调用父类的 onMeasureChild 方法来测量非可滚动子视图的尺寸。
为了让 AppBarLayout 使用我们的自定义 Behavior,我们需要在布局文件中将 app:layout_behavior 属性设置为我们的 Behavior 的全限定名,如下所示:
------------------------------------------------ ------------------------- ----------------------------------- ------------------------------------ -----------------------------------------------------------
这样,当 AppBarLayout 中包含可滚动子视图时,我们的自定义 Behavior 就会生效,保证 AppBarLayout 的高度不受可滚动子视图的影响。
示例代码
下面是一个完整的示例代码,它演示了如何使用自定义 Behavior 来解决 AppBarLayout 高度变化的问题:
------ ----- ------------ ------- ----------------- - --------- --------- ---- --------------- ------------------- - ----------------------------------- --------------------------------------- -------- -------- - ----------------------------- ------ -------- - ------ ----- ----- --- ----- ----------- ---------- ----- --- -- ----- --- ----- --------- -------- ----- -- ---- -- ---- --------- ------ ---- ------- --- - -------- ---------- ------ ----- ------- ----- -- -------- ---- ----- -- ----- --- --- ---- -- ----- ------------ ---------- --- -------- ---- ----- ------- -------- ---- ------ ------- ----- - -------- ---- ----- --- ------ ----------- -------- --- ---- ------- ------- -- ---- ---- -------- -------- ------ --- ---------- ------ --- ---- -------- --------- ----- ---- ------------ ------- -- -------- ----- -- -- ------- --- ------- ----- -- ----------- -------- ----- ----- -------- ----- ----- ------ ---- --- - ---- ----- ------ ------ --------- -- ----- ---- ------------ ------- ----- ------- ---- --------- ----- -- ----- -------- -------- ----- --- -------- ------- ------- ---- --------- ----- ------- ----- -- ----- -------- --- -------- ----- -------- --- --- ------ ------- --------------------------- - ------ ------ ----- ------------------------ ------- --------------------- - ------ -------------------------- - -------- - ------ -------------------------------- -------- ------------ ------ - -------------- ------- - --------- ------ ------- -------------------------------- ------- ------------ ------ --- ----------------------- --- ---------- --- ------------------------ --- ----------- - --- ----------- - -- --- ---- - - -- - - ---------------------- ---- - ---- ---- - -------------------- -- ----- ---------- --------------------- - --- ----------------- - ----------------------------------- ------------------------------ --- ---------------- - --------------------------------------------------- -------------------------- ------------------------------ ------------------- ----------- -- ------------------------- - - --- ----------------- - --------------------------------------------------- - ------------ -------------------------- ---------------------------- ------ ----------------------- ---------- ------------------ ------------ ------ ----- - - -
---------------------------------------------------- ----------------------------------- ------------------------------------- ------------------------------------------------ ------------------------- ----------------------------------- ------------------------------------ ----------------------------------------------------------- ----------------------------------------------------------- ----------------------------------- ------------------------------------ -------------------------------- ---------------------------------- ------------------------- ----------------------------------- ------------------------------------------- ----------------------------- -- ------------------------------------------------------------- -------------------------------------------------- --------- --------------------------- ----------------------------------- ------------------------------------ ------------------- ------- -- ------------------------------------------------------
总结
在本文中,我们介绍了如何解决 Android Material Design AppBarLayout 控件高度变化引起的问题。具体来说,我们使用了一个自定义 Behavior 来覆盖 AppBarLayout 的默认行为,保证 AppBarLayout 的高度不受内部可滚动子视图的影响。这个解决方案可以应用于任何使用 AppBarLayout 的项目中,并且具有一定的深度和学习意义。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65f7a997d10417a2222f1360