常规&高级UI | 青训营笔记

153 阅读7分钟

这是我参与「第四届青训营 」笔记创作活动的第5天


常规&高级UI编程

本堂课内容

  1. UI组件
  2. 布局
  3. 渲染
  4. 交互
  5. 动画
  6. 自定义UI

知识点介绍

UI组件

什么是UI

UI:User Interface,图形用户界面

组件JavaClassPackage
文本组件TextViewandroid.widget.TextView
图片组件ImageViewandroid.widget.ImageView
按钮组件Buttonandroid.widget.Button
输入框组件EditTextandroid.widget.EditText
复选框组件CheckBoxandroid.widget.CheckBox
单选组件RadioButtonandroid.widget.Button

如何学习?

常规view的属性和方法包括通用的属性和方法以及特定的属性和方法。

常规UI组件的使用

屏幕的原点在左上角

margin:组件距离边距的距离。

gravity:子元素在该容器内的对齐方式。

layout_gravity:组件相对于父容器对其方式。

高级UI组件

组件JavaClass
滑动组件ScrollView
列表组件ListView/RecyclerView
下拉刷新组件PullToRefresh
分页组件ViewPager
布局组件LinearLayout/RealtiveLayout

常规UI组件大多是View,高级UI组件大多是ViewGroup,比常规UI组件有更多的功能。

布局

如何将多个UI组件组成一个页面?包含大小,位置,层级等等因素

LinearLayout

常用的,很简单的布局方式——线性布局。按照单一的方向来布局,例如水平、垂直等等方向。

属性功能描述
orientation布局内组件的排列方向
layout_weight布局内组件大小权重
divider布局内组件间分割线
showDividers布局内组件间分割线位置
dividerPadding布局内分割线padding

RelativeLayout

  1. 相对位置,通过与别的组件或者父容器的相对位置来确定。
  2. 可以消除嵌套视图组并使布局层次结构保持扁平化,从而提高性能
  3. 一个RelativeLayout就可以替换多个嵌套的LinearLayout
  4. 适用于复杂场景

FrameLayout

层级布局,与前两种布局方式不同。以层级叠加的方式排列组件,适用于层级排列场景。

属性功能描述
android:foreground前景图像
android:foregroundGravity设置前景图像Gravity

ConstraintLayout

  1. 通过约束组件位置排列组件
  2. 扩展布局方式
  3. 所有视图均根据同级与父布局之间的关系进行布局
  4. 可以使用扁平视图层次结构(无嵌套视图组)创建复杂的大型布局
  5. 适用于复杂场景
  6. 为获得更好的性能和工具支持,推荐使用ConstrainLayout

渲染

页面是如何渲染出来的?分为布局加载、布局解析和UI渲染等部分。

布局加载

  1. 编写布局文件
  2. 注册Manifest
  3. 设置布局文件

布局解析

通过setContentView来创建DecorView,最终有LayoutInflater来加载了XML文件,而LayoutInflater通过解析XML文件,并且根据XML文件生成View实例,并将实例添加到了ViewGroup之中

UI渲染

页面绘制的起点是在onResume之中。

根据Activity的生命周期,在onCreate之中setContentView创建了DecorView,并将layout中的View添加到了DecorView之中,在onResume的ViewRootImpl.requestLayout中触发了页面绘制的部分。

这其中很重要的部分便是Vsync信号,在一个信号之内cpu和gpu需要将整个也页面的布局部分计算出来,并且完成UI渲染的部分,如果在一个信号周期之内没有完成计算,那么将会出现丢帧的现象。这也就解释了为什么手机在高负载的运算条件下会出现丢帧的现象。

交互

分为两个部分:获取View实例,添加相应监听器

回调方法事件监听器
onClick()View.OnClickListener
当用户轻触项目,系统就会调用此方法
onLongClick()View.OnLongClickListener
当用户轻触并按住项目时,系统会调用此方法
onFocusChange()View.OnFocusChangeListener
当用户使用导航键或轨迹球转到或离开项目时,系统会调用此方法
onKey()View.OnFocusChangeListener
当用户聚焦于项目或按下硬件按键时,系统会调用此方法
onTouch()View.OnTouchListener
当用户执行可视为触摸事件的操作时,系统会调用此方法

所有的交互事件都来自于对屏幕触摸信号的处理,View.OnClickListener()等常用点击事件是对交互事件的二次封装

触摸事件

当用户触摸屏幕时,系统将建立一系列的MotionEvent对象,MotionEvent包含关于发生触摸的位置和时间等细节信息,MotionEvent对象被传递到相应的捕获函数中。

View的事件响应

  1. 在onTouchEvent()的ACTION_DOWN设置了一个延时Runnable,用于处理onLongClickListener
  2. 在onTouchEvent()的ACTION_DOWN中,判断onLongClick是否执行,未执行则移除,然后执行onClickListener

事件分发

顺序:Activity->ViewGroup->View

核心方法:

  1. dispatchTouchEvent
  2. onInterceptTouchEvent
  3. onTouchEvent

动画

分为帧动画,补间动画,属性动画

帧动画

作用于视图控件(View),原理为将动画分解为帧的形式,类似于GIF

优点:使用简单、方便,但缺点为功能单一

常常应用于连续性动画

补间动画

常常作用于View,通过确定开始视图样式和结束视图样式,中间样式由系统根据插值器确定来形成完整动画

补间动画常有以下几类

  1. 透明度动画
  2. 旋转动画
  3. 缩放动画
  4. 平移动画

优点:简单,方便

缺点:只能控制视图效果,无法控制属性

常应用于转场动画和视图基础动画

补间动画中的插值器是一个接口,是用来设置属性值从初始值过渡到结束值的变化规律

属性动画

属性动画可以作用于任意Java对象,不在限于视图控件

原理是在指定时间间隔内,通过不断对值的改变与不断将值赋给对象的属性,从而实现该对象在该属性上的动画效果。

特点便是作用对象进行了扩充,不再限于View对象,而且动画效果丰富,不只是补间动画对应的4种动画效果。

常常用于与属性相关、复杂的动画

视图动画和属性动画

  • 视图动画:不改变动画的属性,在动画过程中仅对图像进行变换来达到动画效果。无论动画结果在哪,该View的位置和响应区域都是在原地
  • 属性动画:改变了动画属性,因属性动画在动画过程中对动态改变了对象属性,从而达到了动画效果

自定义View

创建一个自定义View

构造器应用场景
1个参数Java代码中创建View
2个参数通过XML声明创建View
3个参数通过XML声明创建View+Style
4个参数通过XML声明创建View+Style+Theme

处理一个View布局

需要通过重写方法来处理View布局

复写方法应用场景
onMeasure一般需要复写宽高设置为wrap_content场景以及组件宽高有比例限制
onLayout继承自ViewGroup时必须复写,继承自View时一般不用
onSizeChanged视图大小发生改变时候调用

绘制View

通过两个核心类:Paint和Canvas来实现绘制

处理用户交互

交互事件操作逻辑
ACTION_DOWN设置操作状态
ACTION_MOVE处理拖拽,触发UI更新
ACTION_UP处理开关状态,播放动画
ACTION_CANCEL复位操作状态

课后个人总结

通过本堂课认识到了有关UI界面的相关知识,给我的一大感触就是与UI有关的部分内容比之前两节课加起来都要多,感觉对于UI部分的吸收不是很充分,而且老师在上课的时候为了深入讲解有关UI界面的逻辑与内核,放上了许多源码,这对于初学Android的我来说算是比较难理解的部分了。

但是对于常用的布局与UI组件,页面交互与动画的常用知识还是有深刻的了解的。比如说ClickListener有关的部分以及动画相关的部分,只有了解到这些差异才可以在项目开发时候对于使用哪一个有自己的认识与判断。