Android 技术重温系列 (9)- 布局

来源:互联网 发布:java单元测试怎么写 编辑:程序博客网 时间:2024/05/13 14:21

开篇

应用的用户界面包含用户可查看并与之交互的所有内容。Android 提供丰富多样的预置 UI 组件,例如结构化布局对象和 UI 控件,我们可以利用这些组件为我们的应用构建图形界面。Android 还提供其他 UI 模块用于构建特殊的界面,例如对话框、通知和菜单。

随着 Android 版本的不断更新,布局对象有的已经不建议使用,而新的布局可能大家使用的频率也不会太高。所以下面介绍的布局对象可能少了或者不对的地方,麻烦大家尽早告知我一下,我好修改。

LinearLayout

线性布局是一个视图组,用于使所有子视图在单个方向(垂直或水平)保持对齐,使用 android:orientation 属性来指定方向

LinearLayout 的所有子视图一次堆叠,因此无论子视图有多宽,垂直列表每行均只有一个子视图,水平列表将只有一行高(最高子视图的高度加上内边距)。LinearLayout 遵守视图之间的 “margin” 以及每个子视图的 “gravity”(right,left,top,bottom)。

布局权重

LiearLayout 支持使用 android:layout_weight 属性为每个子视图分配权重。此属性根据视图应在屏幕上占据的空间量向视图分配 “weight” 值。权重值大的视图可以填充父视图中任何剩余的空间。子视图可以指定权重值,然后系统会根据子视图声明的权重值比例,将视图中的任何剩余空间分配给子视图。默认权重为 0。

FrameLayou

帧布局为每个加入其中的组件创建一个空白区域,每个子视图占据一帧,这些帧会根据 gravity 属性执行自动对齐。子视图绘制在一个堆内,最近添加的 View 位于顶部。FrameLayout 的大小是其最大的子视图的大小

RelativeLayout

相对布局是一个以相对位置显示子视图的容器。每个视图的位置可以被指定到为相对于同级元素或相对于父元素的位置(例如对齐到底部,左侧或中心)。
RelativeLayout 是设计用户界面常用的布局组件,可以消除嵌套视图组,并使用我们的布局层次结构保持平坦,从而提高性能。

视图定位

RelativeLayout 允许子视图指定他们相对于父视图或彼此的位置(由 ID 指定)。因此,可以通过右边框对齐两个元素或者在另一个元素之间进行对齐,以屏幕为中心,居中左边等等。默认情况下,所有子视图都会绘制在布局左上角,所以我们需要使用 RelativeLayout.LayoutParams 提供的各种布局属性来定义每个视图的位置。

常见的属性如:android:layout_alignParentTop,android:layout_centerVertical,android:layout_below 等

GridLayout

网格布局的作用类似于 HTML 中的 table 标签,它把整个容器划分成 rows/colums 个网格,每个网格可以放置一个组件。除此之外,也可以设置一个组件横跨多少列、一个组件纵跨多少行,可以使用 GridLayout.LayoutParams 提供的各种布局属性来定义组件的布局分布。

ListView

ListView 是一个显示一列可滚动项目的视图组。系统使用 adapter 自动将列表项目插入列表,adapter 从数据源(例如数组或数据库查询)提取内容,并将每个项目结果转换为视图放置到列表中。

使用 Loader

使用 CursorLoader 是以异步任务形式查询 Cursor 的标准方式,可避免查询阻塞应用的主线程。当 CursorLoader 接收到 Cursor 结果时,LoaderCallbacks 会收到对 onLoadFinished() 的回调,从中我们可以使用新的 Cursor 更新 Adapter,然后列表视图会显示结果。

RecyclerView

许多应用程序需要显示基于大数据集或频繁更改的数据的用户界面元素。简单是说法就是它是 ListView 和 GridView 的集合以及优化版本。RecyclerView 及其关联的类和接口可帮助我们设计和实现高效运行的动态用户界面。

动态视图结构

在 RecyclerView 模型下,几个不同的组件一起工作来显示我们的数据。这些组件中的一些可以以未修改的形式使用。例如,应用程序可能直接使用 RecyclerView。在其他情况下,我们提供一个抽象类,让我们对它进行扩展。例如,使用 RecyclerView 的每个应用程序需要定义自己的ViewHolder,它通过扩展抽象 RecyclerView.ViewHoler 类来实现

动态用户界面的整体容器是 RecyclerView 对象。将此对象添加到 Fragment 或 Activity 的布局中后,RecyclerView 自动填充代表带个项目的视图中去。RecyclerView 使用我们提供的布局管理器来排列项目。我们可以使用标准的布局管理器(如 LinearLayoutManager 或 GridLayoutManager),或使用我们自己定义的布局管理器。

各个 item 项由 ViewHolder 对象表示。这些对象时通过扩展 RecyclerView.ViewHolder 定义的类的实例。每个 ViewHolder 负责显示单个 item,并具有自己的视图。例如,如果 RecyclerView 用于显示用户的音乐收藏,则每个 ViewHolder 可以表示单个相册。在这种情况下,ViewHolder 的视图可能包含显示相册标题和图稿的元素,并且可能会通过播放和暂停该相册来响应点击。RecycleView 创建的 ViewHolder 只需要显示动态内容的屏幕部分所需的数量。当用户滚动列表时,RecyclerView 会将屏幕外视图重新绑定到滚动到屏幕上的数据。

ViewHolder 对象由适配器管理,我们可以扩展 RecyclerView.Adapter 抽象类来创建。适配器根据需要创建视图并且绑定对应的数据。它通过将 ViewHolder 分配到某个位置,并调用 onBindViewHolder() 方法来实现。该方法使用 ViewHolder 的位置来确定内容应该是什么。

RecyclerView 模型下进行了大量优化工作,因此我们不必进行下面的操作:
- 当视图首次填充时,它将创建并绑定任意一个 ViewHolder。例如,如果视图显示相册 0 到 9,则 RecyclerView 会创建并绑定 ViewHolder,这样,用户滚动到列表,则下一个元素已经准备好显示了
- 当用户滚动列表时,RecyclerView 会根据需要创建新的 ViewHolder,它还保存了屏幕滚动的 ViewHolder,因此可以重复使用。如果用户切换他们正在滚动的方向,则可以直接将从屏幕上滚动的 ViewHolder 带回。另一方面,如果用户按照相同的方向滚动,则屏幕最新的 ViewHolder 可以显示最新的数据,而 ViewHolder 不需要重新创建或重新加载视图,相反,应用程序只是更新视图的内容以匹配其绑定的 item 项。
- 当显示的 item 更改时,应用程序通过调用适当的 RecycleView.Adapter.notify() 方法通知适配器。适配器的内置代码会重新绑定受影响的 item 项。

RecyclerView 工作流程
  1. 在 Activity 的 onCreate() 方法中创建布局中的 RecyclerView
  2. 在 onCreate() 方法中创建一个适配器。适配器类扩展了 Android 支持库的 RecyclerView.Adapter 类。通常,当应用程序创建适配器时,同时传递适配器所需的数据信息
  3. 将适配器添加到 RecycleView
  4. 指定适配器所需的 ViewHolder 类型
  5. 系统调用该适配器的 onCreateViewHolder() 方法。该方法需要构建 ViewHolder 并设置用于显示内容的视图。
  6. 然后,Android 支持库会将 ViewHolder 绑定其数据。它通过调用适配器的 onBindViewHolder() 方法并将 ViewHolder 的位置传递到 RecycleView 中来实现。onBindViewHolder() 方法需要获取相应的数据,并使用它来填充 ViewHolder 的布局
  7. Android 支持库重复此过程,创建和绑定新的 ViewHolder,直到 RecyclerView 的可见部分被填充完毕。

如果用户滚动列表,Android 支持库将已经准备好的 ViewHolder 带入视图,并根据需要创建并绑定新视图。它不会立即摧毁屏幕以外的 ViewHolder,为了防止一欧诺个户回滚,它们保持可用状态。但是在创建了一定数量的 ViewHolder 后,Android 支持库不会创建新的,相反,它会根据需要重新绑定现在的 Viewholder,通过调用 onBindViewHolder() 为它们指定一个新的位置,并更新内容。

如果列表更改,应用程序将调用适当的 RecyclerView.Adapter 通知方法。Android 支持库通过重新绑定任何受影响的 Viewholder 来响应通知,允许更新其诗句。

自定义 RecyclerView

我们可以自定义 RecyclerView 对象以满足特定需求。标准类提供大多数开发人员需要的所有功能;在许多情况下,我们需要做的唯一自定义是为每个 ViewHolder 设计视图,并编写代码以实用是的那个的数据更新这些视图。

修改布局

RecyclerView 使用布局管理器来排列屏幕上的各个数据项。Android 支持库包括三个标准布局管理器,每个管理器都提供许多自定义选项:
- LinearLayoutManager 将 item 排列在一维列表中。与 LinearLayoutManager 一起使用 RecyclerView 可提供旧版 ListView 布局的功能
- GridLayoutManager 将 item 排列在 二维网格中,如棋盘上的正方形。与 GridLayoutManager 一起使用 RecyclerView 可提供像旧版的 GridView 布局的功能
- StaggeredGridLayoutManagerManager 将 item 排列在 二维网格中,每列与之前的列稍微偏移,如美国国旗中的星

如果这些布局管理器都不适合我们的需要,则可以通过扩展 RecyclerView.LayoutManager 抽象类来创建自己的布局管理器

item 动画

每当一个 item 更改时,RecycleView 使用一个动画来改变它的外观。这个动画是一个扩展了 RecyclerView.ItemAnimator 抽象类的对象。默认情况下,RecycleView 使用 DefaultItemAnimator 来提供动画。

ScrollView

用于可由用户滚动的视图层次结构的布局容器,允许其大于物理显示。一个 ScrollView 是一个 FrameLayout,这意味着我们应该防止一个 Child 包含整个内容滚动,这个 Child 可能是具有复杂层次结构对象的布局管理器。经常使用的场景是一个垂直方向的 LinearLayout,呈现用户可以滚动的垂直阵列。

我们不应该使用具有 ListView 的 ScrollView,因为 ListView 负责自己的垂直滚动。最重要的是,这样做会使 ListView 中的所有重要优化失败,以处理大型列表,因为它有效的强制 ListView 显示完整的 item 列表,以填补 ScrollView 提供的容器。

TextView 类也可以自己滚动,所以不需要一个 ScrollView,但是使用这两个可以在更大的容器中实现文本视图的效果

如果需要水平滚动,请使用 HorizontalScrollView

DrawerLayout

DrawerLayout 作为窗口内容的顶层内容,运行从窗口的一个或两个垂直边缘拉出交互式 “Drawer” 视图。

抽屉定位和布局使用 android:layout_gravity 属性来控制,该属性对应于我们希望抽屉从哪个方面出现的视图:左侧或右侧。值得注意的是,窗口的每个垂直边缘只能有一个抽屉视图。如果我们的布局在窗口的每个垂直边缘配置多个抽屉视图,则会在运行时抛出异常

要使用 DrawerLayout,将主内容视图定位为第一个宽度和高度 match_parent 的 Child,在主内容视图之后添加抽屉作为子视图,并适当的设置 layout_gravity。抽屉通常使用 match_parent 为高度固定宽度

DrawerLayout.DrawerListener 可用于监视抽屉视图的状态和运动。避免在动画过程中执行耗时的操作,导致动画过程中卡顿。对于耗时操作可以在 STATE_IDLE 状态下执行。

DrawerLayout.SimpleDrawerListener 提供每个回调方法的默认/无操作实现

根据 Android Design,任何未予左侧/开头的抽屉应始终包含用于在应用程序中导航的内容,而位于右侧/末端的任何抽屉应始终包含执行当前内容的操作。这保留了与行动栏和其他地方相同的向导,行动权限结构。

SwipeRefreshLayout

只要用户可以通过垂直滑动手势刷新视图的内容,就应该使用 SwipeRefreshLayout。实例化此视图的 Activity 应该添加一个 OnRefreshListener,以便在刷新手势完成时通知它。

SwipeRefreshLayout 将在每次手势再次完成时通知监听器,监听器负责正确确定何时实际启动其内容刷新。如果确定不用刷新,可以调用 setRefreshing(false) 来取消刷新的任何可视指示。乳沟 Activity 希望仅显示进度动画,则应调用 setRefreshing(true)。要禁用手势和进度动画,可以在视图上调用 setEnable(false)

该布局应该是由于手势而被刷新的视图的父级,并且只能支持一个直接的 child。此视图也将作为手势的目标,并将被强制匹配此布局汇总提供的宽度和高度。 SwipesRefreshLayout 不提供辅助功能事件,相反,必须提供菜单项与允许在使用该手势的地方刷新内容

AppBarLayout

AppBarLayout 是一个垂直的 LinearLayout,他实现了 material designs 应用程序栏概念的许多功能,即滚动手势。

Children 应该通过 setScrollFlags(int) 和相关联的布局 xml 属性的 app:layout_scrollFlags 提供他们所需的滚动行为

这个视图很大程度上取决于在 CoordinatorLayout 中作为一个直接的 child。如果我们在不同的 ViewGroup 中使用 AppBarLayout,它的大部分功能将无法正常工作。

AppBarLayout 还需要一个单独的滚动兄弟,以便指导何时滚动。绑定时通过 AppBarLayout.ScrollingViewBehavior 行为类完成的,这意味着我们应该将滚动视图的行为设置为 AppBarLayout.ScrollingViewBehavior 的一个实例。

TabLayout

TagLayout 提供一个水平布局来显示选项卡。要显示的选项卡的内容是通过 TabLayout.Tab 实例完成的。我们可以通过 newTab() 创建选项卡,从那里可以分别通过 setText(int) 和 setIcon(int) 来更改选项卡的标签或图标。要显示该选项卡,我们需要通过其中一个 addTab(Tab) 方法将其添加到布局。

我们应该通过 setOnTabSelectedListener(OnTabSelectedListener) 设置监听器,以便在任何选项卡的选择状态已更改时通知。

集成 ViewPager

如果我们正在使用 ViewPager 与此布局,可以调用 setupWithViewPager(ViewPager) 将两者连接在一起。该布局将从 PagerAdapter 的页面标题自动填充。该视图还支持用作 ViewPAger 的装饰的一分部,并且可以直接添加到布局资源文件中的 ViewPager 中

CoordinatorLayout

CoordinatorLayout 是一个功能抢到的 FrameLayout。CoordinatorLayout 适用于两个主要场景:
- 作为根节点或嵌套布局作为与一个或多个子视图进行特定交互的容器。
- 通过为 CoordinatorLayout 的子视图指定 Behaviors,我们可以在单个父项中提供许多不同的交互,并且这些视图也可以彼此交互。当使用 DefaultBehavior 注释作为 CoordinatorLayout 的子级时,View 类可以指定默认行为。

行为可以用于实现各种互动和附加的布局修改,从滑动抽屉和面板到滑动拆卸元件和按钮,随着移动和动画,它们会粘附到其他元素上。

children 可以制定 inserEdge 来描述视图如何插入 CoordinatorLayout。设置为通过 dodgeInserEdges 闪避相同插入边的任何子视图将被适当的移动,以便视图不重叠。

小结

这篇内容属于浅层次的内容介绍,代码案例什么的没有写,不要说我懒哦,而是需要介绍的基础知识还有很多。更多的情况是当你了解了还有这些布局后自己编写代码在解决问题。

这篇原本要在上周完成并发出的,因为上周老妈从老家来杭州呆了一周,照顾我和我再过两个月就生产的老婆,所以上周有空余时间都陪着老妈和老婆了。加上周末是 520 ,上周虽然学习进度没怎么提升,但身心上还是比较放松的。这周一开始就奋斗了,上周没完成的两篇,还有周需要完成的任务,好好努力吧。