首页 > 其他分享 >Android:如何绘制View

Android:如何绘制View

时间:2024-07-08 23:55:46浏览次数:19  
标签:遍历 父级 int 布局 子级 Android 绘制 View

点击查看Android 如何绘制视图官网

一、简介

Android 框架会在 Activity 获得焦点时请求 Activity 绘制其布局。Android 框架会处理绘制流程,但该 Activity 必须提供其布局层次结构的根节点。

Android 框架会绘制布局的根节点,并测量和绘制布局树。它会通过遍历布局树并渲染与无效区域相交的每个 View 进行绘制。每个 ViewGroup 负责请求绘制其每个子级(使用 draw() 方法),而每个 View 负责绘制其本身。由于布局树已经过系统预先遍历,因此该框架会在子级之前(即后方)绘制父级,而其同级会按照它们在布局树中出现的顺序进行绘制。

注意:该框架不会绘制有效区域之外的 View 对象,也不会负责为您绘制 View 背景。您可以通过调用 invalidate() 来强制绘制 View。

Android 框架绘制布局包含两个遍历流程一个测量遍历和一个布局遍历。该框架会在 measure(int, int) 中执行测量遍历,并执行 View 树的自上而下遍历。在递归过程中,每个 View 都会将维度规范下推到布局树。测量遍历结束时,每个 View 都会存储其测量值。该框架会在 layout(int, int, int, int) 中执行第二次遍历,也是自上而下遍历。在此次遍历中,每个父级负责使用测量遍历中计算的尺寸来定位其所有的子级。

以下各部分更详细地介绍了布局流程的两个遍历。

二、启动测量遍历

当返回 View 对象的 measure() 方法时,请设置其 getMeasuredWidth() 和 getMeasuredHeight() 值,以及 View 对象的所有后代的值。View 对象的测量宽度值和测量高度值必须遵守 View 对象的父级所施加的限制。这有助于保证在测量遍历结束时,所有父级都会接受其子级的所有测量值。

父级 View 可以对其子级多次调用 measure()。例如,父级可以使用未指定的维度测量子级一次,以确定它们的首选尺寸。如果子级的不受限尺寸的总和过大或过小,则父级可以使用限制子级尺寸的值再次调用 measure()。

测量遍历使用两个类来传达维度。View 对象使用 ViewGroup.LayoutParams 来传达其首选尺寸和位置。基本 ViewGroup.LayoutParams 类描述了 View 的首选宽度和高度。针对每个维度,它可以指定以下某一项:

  • 一个确切的尺寸。
  • MATCH_PARENT,此参数意味着 View 的首选尺寸是其父级的尺寸(负填充)。
  • WRAP_CONTENT,此参数意味着 View 的首选尺寸恰好足以容纳其内容(正填充)。

有适用于 ViewGroup 的不同子类的 ViewGroup.LayoutParams 子类。例如,RelativeLayout 有自己的 ViewGroup.LayoutParams 子类,其中包括可使子级 View 对象水平居中和垂直居中的功能。

MeasureSpec 对象用于在树中将要求从父级下推到子级。MeasureSpec 可以是下述三种模式之一:

  • UNSPECIFIED:父级使用此模式来确定子级 View 的目标维度。例如,LinearLayout 可对高度设置为 UNSPECIFIED 且宽度设置为 EXACTLY 240 的子级调用 measure(),以确定给定宽度为 240 像素的子级 View 所需的高度。
  • EXACTLY:父级使用此模式来强制子级使用某个确切尺寸。子级必须使用此尺寸,并保证其所有的后代都能放入此尺寸。
  • AT MOST:父级使用此模式来强制规定子级的最大尺寸。子级必须保证它及其所有的后代都能放入此尺寸。

三、启动布局遍历

如需启动布局,请调用 requestLayout()。当 View 认为自己无法再放入当前范围时,通常会调用此方法。

四、实现自定义测量和布局逻辑

如果您要实现自定义测量或布局逻辑,请替换实现该逻辑的方法:onMeasure(int, int) 和 onLayout(boolean, int, int, int, int)。 这些方法分别由 measure(int, int) 和 layout(int, int, int, int) 调用。请勿尝试替换 measure(int, int) 或 layout(int, int) 方法 - 这两种方法都是 final,因此无法被替换。

以下示例展示了如何在 WindowManager 示例应用的“SplitLayout”类中执行此操作。如果 SplitLayout 具有两个或更多子视图,并且显示屏具有折叠边,则它会将两个子视图放置在折叠边的任一侧。以下示例展示了用于替换测量和布局的用例,但对于生产环境,请使用 SlidingPaneLayout(如果您希望出现此行为)。

/**
 * An example of split-layout for two views, separated by a display
 * feature that goes across the window. When both start and end views are
 * added, it checks whether there are display features that separate the area
 * in two—such as a fold or hinge—and places them side-by-side or
 * top-bottom.
 */
class SplitLayout : FrameLayout {
   private var windowLayoutInfo: WindowLayoutInfo? = null
   private var startViewId = 0
   private var endViewId = 0

   private var lastWidthMeasureSpec: Int = 0
   private var lastHeightMeasureSpec: Int = 0

   ...

   fun updateWindowLayout(windowLayoutInfo: WindowLayoutInfo) {
      this.windowLayoutInfo = windowLayoutInfo
      requestLayout()
   }

   override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
      val startView = findStartView()
      val endView = findEndView()
      val splitPositions = splitViewPositions(startView, endView)

      if (startView != null && endView != null && splitPositions != null) {
            val startPosition = splitPositions[0]
            val startWidthSpec = MeasureSpec.makeMeasureSpec(startPosition.width(), EXACTLY)
            val startHeightSpec = MeasureSpec.makeMeasureSpec(startPosition.height(), EXACTLY)
            startView.measure(startWidthSpec, startHeightSpec)
            startView.layout(
               startPosition.left, startPosition.top, startPosition.right,
               startPosition.bottom
            )

            val endPosition = splitPositions[1]
            val endWidthSpec = MeasureSpec.makeMeasureSpec(endPosition.width(), EXACTLY)
            val endHeightSpec = MeasureSpec.makeMeasureSpec(endPosition.height(), EXACTLY)
            endView.measure(endWidthSpec, endHeightSpec)
            endView.layout(
               endPosition.left, endPosition.top, endPosition.right,
               endPosition.bottom
            )
      } else {
            super.onLayout(changed, left, top, right, bottom)
      }
   }

   /**
   * Gets the position of the split for this view.
   * @return A rect that defines of split, or {@code null} if there is no split.
   */
   private fun splitViewPositions(startView: View?, endView: View?): Array

在这里插入图片描述

五、SlidingPaneLayout

5.1 创建双窗格布局

SlidingPaneLayout 组件支持在较大的设备和可折叠设备上并排显示两个窗格,同时自动进行调整,以便在手机等较小的设备上一次仅显示一个窗格。

5.2 添加依赖

如需使用 SlidingPaneLayout,请在应用的 build.gradle 文件中添加以下依赖项:

dependencies {
    implementation "androidx.slidingpanelayout:slidingpanelayout:1.2.0"
}
5.4 XML 布局配置

SlidingPaneLayout 提供一种水平的双窗格布局,可在界面的顶层使用。在这种布局中,第一个窗格用作内容列表或浏览器,从属于另一个窗格中用于显示内容的主要详细信息视图。

在这里插入图片描述

六、SlidingPaneLayout 示例

点击查查GitHub 上的 SlidingPaneLayout 示例

标签:遍历,父级,int,布局,子级,Android,绘制,View
From: https://blog.csdn.net/ChinaDragon10/article/details/140253670

相关文章

  • Android 10.0 SystemUI启动流程
    1、手机开机后,Android系统首先会创建一个Zygote(核心进程)。2、由Zygote启动SystemServer。3、SystemServer会启动系统运行所需的众多核心服务和普通服务、以及一些应用及数据。例如:SystemUI启动就是从SystemServer里启动的。4、进入锁屏界面,开机完成。SystemServer中......
  • 晚上定时编译android系统
    1、问题可能偶然想晚上定时编译android系统2、解决at.sh#!/bin/sh#at-fat.shnow+1min#at-lset-eset-xecho$SHELLecho'atbuildbegin'/bin/date>>at_build.log/bin/bash-c'sourcebuild/envsetup.sh>>at_build.log2>&1;lu......
  • Android开发——使用Android Studio封装SDK(二) jar
    前言:什么叫SDK?  软件开发工具包(SoftwareDevelopmentKit,缩写SDK)一般是一些软件工程师为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件时的开发工具的集合。  Android常见的SDK有哪些形式?   (1).so库:是C或C++语言而打包成的库。   (2)......
  • 类图、时序图、状态图绘制神器,程序猿们有福了。
    对于程序员来说,绘制类图、时序图、状态图等UML图是一个令人头疼且耗时耗力的过程。即使是经验丰富的程序员,也常常在绘图过程中感到困扰和不便。传统的绘图工具往往需要用户手动进行繁琐的操作,既浪费时间又容易出错。而且,即便是完成了绘图,也难以保证图表的准确性和规范性......
  • turtle绘制五星红旗
    importturtle#背景色turtle.bgcolor('red')turtle.color('yellow')#画笔颜色turtle.fillcolor('yellow')#填充色turtle.up()turtle.goto(-600,180)turtle.down()#主星turtle.begin_fill()#开始着色foriinrange(5):turtle.forward(50)......
  • 通过高德地图 JS API实现 鼠标绘制多边形
    效果图:  核心代码:<template><a-modaltitle="选择地图所在位置":width="width":visible="visible"@ok="handleOk"@cancel="handleCancel"cancelText="关闭"><divclass="location-map-box&......
  • Overview and Stream Cipher
    CryptographyCourseNotesCourseOverviewThegoalofthiscourseistoteachyouhowcryptoprimitivesworkhowtousethemcorrectlyandreasonaboutthesecurityofyourconstructions.Inthiscourse,youwilllearnsomeabstractsofsomecryptography......
  • python:使用matplotlib库绘制图像(一)
    作者是跟着http://t.csdnimg.cn/4fVW0学习的,matplotlib系列文章是http://t.csdnimg.cn/4fVW0的自己学习过程中整理的详细说明版本,对小白更友好哦!一、Matplotlib图像基础1.1 基本绘图实例:sin、cos函数图代码详解:1.frompylabimport*:导入pylab库中所有函数和变量。pyla......
  • 手机数据恢复:如何在没有root的情况下恢复Android数据?
    您是否不小心从Android设备中删除了重要数据?您是否担心如何取回您的照片、视频和文档?有时,我们不小心删除了重要数据,并使用Androidroot方法取回文件。许多用户不喜欢root他们的Android设备,因为这是一种复杂的方法。在本指南中,我们将告诉您如何使用最好的Android数据恢复软件奇......
  • iOS开发-WKWebView的介绍与基本使用
    WKWebView是iOS开发中用于显示网页内容的组件,它是在iOS8中引入的,作为UIWebView的替代品。WKWebView提供了更高的性能和更多的功能,它是基于WebKit引擎的,这也是Safari浏览器所使用的引擎。主要特性性能提升:相比于老旧的UIWebView,WKWebView在性能上有显著提升,包括......