Android:如何绘制View

news2024/11/16 4:45:14

点击查看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 示例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1923642.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【每日一练】python类和对象现实举例详细讲解

""" 本节课程目的: 1.掌握类描述现实世界实物思想 2.掌握类和对象的关系 3.理解什么事面向对象 """ #比如设计一个闹钟,在这里就新建一个类 class Clock:idNone #闹钟的序列号,也就是类的属性priceNone #闹…

Redis学习笔记(个人向)

Redis学习笔记(个人向) 1. 概述 是一个高性能的 key-value 数据库;其具有以下三个特点: Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。Redis不仅仅支持简单的key-value类型的数据&…

Nginx+Keepalive调度的高可用

nginxkeepalive: 调度器的高可用 vip地址主备之间的切换,主在工作时,p地址只在主上,主停止工作,p飘移到备服务器。 在主备的优先级不变的情况下,主恢复工作,vp会飘回到主服务器。 1、配优先级 2、配置…

EventBus学习

视频:05_尚硅谷_EventBus_粘性事件案例_哔哩哔哩_bilibili 1.整体框架 2.demo下载地址:https://github.com/greenrobot/EventBus 3.实现非粘性时间流程: 3.1导入架包eventbus-3.0.0.jar和eventbus-3.0.0-sources.jar 3.2在接受数据页面注…

k8s(五)---名称空间

五、名称空间 名称空间是k8s划分不同工作空间的逻辑单位,是k8s资源逻辑隔离的机,。可以给不同的租户,不同的环境、不同的项目创建对应的命名空间。 1、查看名称空间 kubectl get ns kubectl get namespaces 此处展示了四个命名空间 2、管理名称空间 1…

更新商品前端接口编写

文章目录 新增页面书写写表单价格符号的显示然后状态的书写后端枚举书写时间书写使用组件 新增页面书写 书写直接复制页面 写表单的绑定信息 然后绑定表单 表单绑定还有表单数据的绑定 标签中ref的作用就是将 该组件注册到vue对象的ref属性中 那么在vue运行的时候,会加载所…

IOC、DI<4> Unity、AOP、MVCAOP、UnityAOP 区别

IOC():控制反转,把程序上层对下层的依赖,转移到第三方的容器来装配 是程序设计的目标,实现方式包含了依赖注入和依赖查找(.net里面只有依赖注入) DI:依赖注入&#xff0c…

【网络文明】关注网络安全

在这个数字化时代,互联网已成为我们生活中不可或缺的一部分,它极大地便利了我们的学习、工作、娱乐乃至日常生活。然而,随着网络空间的日益扩大,网络安全问题也日益凸显,成为了一个不可忽视的全球性挑战。认识到网络安…

Gitee简易使用流程(后期优化)

目录 1.修改用户名 2.文件管理 新建文件/文件夹流程如下: 上传文件流程如下: 以主页界面为起点 1.修改用户名 点解右上角的头像--> 点击“账号设置” 点击左边栏里的“个人资料“ 直接修改用户名即可 2.文件管理 选择一个有修改权限仓库&#…

【轻松拿捏】Java-final关键字(面试)

目录 1. 定义和基本用法 回答要点: 示例回答: 2. final 变量 回答要点: 示例回答: 3. final 方法 回答要点: 示例回答: 4. final 类 回答要点: 示例回答: 5. final 关键…

yolov8预测

yoloV8 官方地址 预测 -Ultralytics YOLO 文档 1.图片预测 from ultralytics import YOLO #### 图片预测1 ### https://www.youtube.com/watch?vneBZ6huolkg ### https://github.com/ultralytics/ultralytics ### https://github.com/abdullahtarek/football_analysis…

Linux C语言基础 day10

目录 学习目标: 学习内容: 1.指针指向数组 1.1 指针与数组的关系 1.2 指针与一维数组关系实现 1.2.1 指针与一维数组的关系 1.2.2 指针指向一维整型数组作为函数参数传递 课外作业: 学习目标: 一周掌握 C基础知识 学习内…

专业条码二维码扫描设备和手机二维码扫描软件的区别?

条码二维码技术已广泛应用于我们的日常生活中,从超市结账到公交出行,再到各类活动的入场验证,条码二维码的便捷性不言而喻,而在条码二维码的扫描识别读取过程中,专业扫描读取设备和手机二维码扫描软件成为了两大主要工…

uniapp使用多列布局显示图片,一行两列

完整代码&#xff1a; <script setup>const src "https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/shuijiao.jpg" </script><template><view class"content"><view class"img-list"><image :src"src…

日志自动分析-操作系统-GscanLogonTracerf8x

&#x1f3bc;个人主页&#xff1a;金灰 &#x1f60e;作者简介:一名简单的大一学生;易编橙终身成长社群的嘉宾.✨ 专注网络空间安全服务,期待与您的交流分享~ 感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持&#xff01;❤️ &#x1f34a;易编橙终身成长社群&#…

TCP连接的三次握手和断开的四次挥手

TCP连接的建立过程通过三次握手完成&#xff0c;‌而连接的关闭过程则通过四次挥手完成。‌ 三次握手&#xff1a;‌这是TCP连接建立的过程&#xff0c;‌主要目的是确保双方都准备好进行数据传输。‌具体步骤如下&#xff1a;‌ 客户端向服务器发送一个SYN报文&#xff0c;‌请…

Canvas:实现在线动态时钟效果

想象一下&#xff0c;用几行代码就能创造出如此逼真的图像和动画&#xff0c;仿佛将艺术与科技完美融合&#xff0c;前端开发的Canvas技术正是这个数字化时代中最具魔力的一环&#xff0c;它不仅仅是网页的一部分&#xff0c;更是一个无限创意的画布&#xff0c;一个让你的想象…

利用宝塔安装一套linux开发环境

更新yum&#xff0c;并且更换阿里镜像源 删除yum文件 cd /etc/yum.repos.d/ 进入yum核心目录 ls sun.repo rm -rf * 删除之前配置的本地源 ls 配置阿里镜像源 wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo 配置扩展包 wge…

【JavaScript 算法】深度优先搜索:探索所有可能的路径

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、算法原理二、算法实现三、应用场景四、优化与扩展五、总结 深度优先搜索&#xff08;Depth-First Search, DFS&#xff09;是一种用于遍历或搜索图或树数据结构的算法。该算法尽可能深入图的分支&#xff0c;探索所有可…

【Lora模型推荐】Stable Diffusion创作具有玉石翡翠质感的图标设计

站长素材AI教程是站长之家旗下AI绘图教程平台 海量AI免费教程&#xff0c;每日更新干货内容 想要深入学习更多AI绘图教程&#xff0c;请访问站长素材AI教程网&#xff1a; AI教程_深度学习入门指南 - 站长素材 (chinaz.com) logo版权归各公司所有&#xff01;本笔记仅供AIGC…