整理旧电脑上的一些笔记
前言
- ConstraintLayout核心用法详解(一):相对定位、边距、偏移与环形定位
- ConstraintLayout核心用法详解(二):尺寸约束与链约束
- ConstraintLayout核心用法详解(三):引导线、屏障、组和占位
- ConstraintLayout核心用法详解(四):ConstraintSet、MotionLayout与Flow
今天继续整理ConstraintLayout。
ConstraintLayout的特点:
- 扁平布局,无嵌套,一个层级就可以绘制复杂布局;
- 渲染性能高;
- 集合了线性布局、相对布局、百分比布局的特点和大多数功能;
- 支持可视化环境下拖拽绘制约束布局;
- 轻松地为应用中使用的 UI 组件添加动画效果。
1. Layer
Layer是ConstraintLayout 2.0加入的新的辅助类,它同Guideline、Group类似都是虚拟辅助。Layer是用来控制一组视图的移动和旋转,它和Group的场景不一样,Group是用来简单控制视图的可见性(VISIBILITY或INVISIBILITY)。
我们可以把Layer的效果看成是一个ViewGroup,但是实际书写代码中并不需要把 view 包裹进去Layer。
下面看具体 XML 代码示例:
<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".constraintlayout.LayerActivity"><ImageViewandroid:id="@+id/iv_android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="50dp"android:src="@mipmap/ic_launcher"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"/><TextViewandroid:id="@+id/tv_android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:text="android"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@id/iv_android"/><androidx.constraintlayout.helper.widget.Layerandroid:id="@+id/layer"android:layout_width="wrap_content"android:layout_height="wrap_content"app:constraint_referenced_ids="iv_android,tv_android"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"/><Buttonandroid:id="@+id/btn_rotation"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="rotation"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"/></androidx.constraintlayout.widget.ConstraintLayout>上面 XML 代码中关键属性:
- constraint_referenced_ids:指定要控制的视图ID,如iv_android、tv_android,逗号分隔
Kotlin 代码示例:
classLayerActivity:AppCompatActivity(){overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)setContentView(R.layout.activity_layer)vallayer=findViewById<Layer>(R.id.layer)valbutton=findViewById<Button>(R.id.btn_rotation)button.setOnClickListener{valanimator=ValueAnimator.ofFloat(0f,360f)animator.duration=2000animator.addUpdateListener{animator->layer.rotation=animator.animatedValueasFloat layer.scaleX=2.0flayer.scaleY=2.0flayer.translationX=100flayer.alpha=0.3f}animator.start()}}}上面代码因为比较简单,直接使用Kotlin原始方法findViewById,实际推荐使用viewBinding,减少模板代码。
运行效果图:
2.ImageFilterView 和 ImageFilterButton
ImageFilterView和ImageFilterButton也都是ConstraintLayout 2.0新添加的控件。它是 Android 第一次提供原生支持图像圆角、滤镜(饱和度、亮度、对比度和色温)、交叉淡入(crossfade)等特性。
以往产品中遇到需要圆角图形,如头像、歌曲专辑封面等,往往采用自定义View或第三方控件实现,有了ImageFitlerView就很好的解决了该场景问题。
2.1 ImageFilterView
首先介绍ImageFilterView支持的属性:
- altSrc:设置一个和src属性不同的图,用来实现交叉淡入淡出效果
- saturation:设置饱和度。其中0=灰度,1=原始图,2=超饱和
- brightness:设置亮度。0=全黑,1=原始图,2=亮度加倍
- warmth:设置色温。1=中性,2=暖色,0.5=冷色
- contrast:设置图像对比度。1=不变,0=灰色,2=高对比度
- crossfade:设置两张图像间的混合程度。0=完全显示src图,1=完全显示altSrc图像
- round:设置圆角半径
- roundPercent:设置圆角半径为短边长的一个比例值
- overlay:设置替代图(altSrc)是以叠加方式淡入原始图像上还是与原始图像进行交叉淡入淡出。默认=true
XML代码展示:
<androidx.constraintlayout.utils.widget.ImageFilterViewandroid:id="@+id/iv_avatar"android:layout_width="100dp"android:layout_height="100dp"android:src="@drawable/img_avatar"app:altSrc="@drawable/img_duck"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:round="20dp"/>Kotlin代码展示:
binding.sliderSaturation.addOnChangeListener{slider,value,fromUser->if(fromUser){valintValue=value.toInt()Toast.makeText(this,"$intValue",Toast.LENGTH_SHORT).show()when(intValue){0->binding.ivAvatar.saturation=0f1->binding.ivAvatar.saturation=1f2->binding.ivAvatar.saturation=2f}}}binding.sliderBrightness.addOnChangeListener{slide,value,fromUser->if(fromUser){valintValue=value.toInt()when(intValue){0->binding.ivAvatar.brightness=0f1->binding.ivAvatar.brightness=1f2->binding.ivAvatar.brightness=2f}}}binding.sliderWarmth.addOnChangeListener{slide,value,fromUser->if(fromUser){valfloatValue=value.toFloat()when(floatValue){0.5f->binding.ivAvatar.warmth=0.5f1.0f->binding.ivAvatar.warmth=1f2.0f->binding.ivAvatar.warmth=2f}}}binding.sliderContrast.addOnChangeListener{slide,value,fromUser->if(fromUser){valintValue=value.toInt()when(intValue){0->binding.ivAvatar.contrast=0f1->binding.ivAvatar.contrast=1f2->binding.ivAvatar.contrast=2f}}}binding.seekbarCrossfade.setOnSeekBarChangeListener(object:SeekBar.OnSeekBarChangeListener{overridefunonProgressChanged(seekbar:SeekBar?,progress:Int,fromUser:Boolean){if(fromUser){valpercentage=progress/100.0fbinding.ivAvatar.crossfade=percentage}}overridefunonStartTrackingTouch(seekbar:SeekBar?){}overridefunonStopTrackingTouch(seekbar:SeekBar?){}})整体的代码示例还是很简单的,我们结合下面的效果图来加深理解即可。
2.2 ImageFilterButton
ImageFilterButton是AppCompatImageButton的子类,可以用来显示、组合和过滤图像。它与上面提到的ImageFilterView拥有相同的属性,所不一样的就是ImageFilterButton兼具 Button 的特性。
直接XML代码展示:
<androidx.constraintlayout.utils.widget.ImageFilterButtonandroid:id="@+id/btn_share"android:layout_width="80dp"android:layout_height="80dp"android:layout_marginTop="20dp"android:background="#E91E63"android:src="@drawable/icon_share"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@id/seekbar_crossfade"app:round="40dp"/><androidx.constraintlayout.utils.widget.ImageFilterButtonandroid:id="@+id/btn_favorite"android:layout_width="80dp"android:layout_height="80dp"android:layout_marginTop="20dp"android:background="#E91E63"android:src="@drawable/icon_favorite"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@id/btn_share"app:round="40dp"/>效果图:
ImageFilterButton还是比较好理解的,它支持的饱和度、对比度等特性参考上面ImageFilterView示例,这里也就不再赘述了。
3. MockView
讲解MockView前先来看一张图。
一些产品稿中会使用上图中带对角线的矩形来占位,方便模拟一些视图,而MockView也正是这样的用途。
A view that is useful for prototyping layouts.
MockView在布局中作为占位视图,模拟真实数据或复杂视图的布局效果。实际开发中,存在下面的场景:
- 真实数据还没有,比如用户头像;
- 某些View是动态加载的,比如RecyclerView加载的item;
- 某些View是有不同的状态的,比如loading、空数据提示
我们当然可以在 Java(Kotlin) 中用代码模拟假数据来实现UI效果,但当我们使用ConstraintLayout作为根布局时候,更推荐MockView来模拟这些数据存在。
下面是MockView的一些属性:
- mock_label:显示字体
- mock_labelColor:字体颜色
- mock_labelBackgroundColor:字体背景色
- mock_diagonalsColor:对角线颜色
- mock_showDiagonals:是否显示对角线
XML代码示例:
<androidx.constraintlayout.utils.widget.MockViewandroid:id="@+id/background"android:layout_width="0dp"android:layout_height="100dp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:mock_label="LOGO或风景图"app:mock_labelBackgroundColor="#9C27B0"app:mock_labelColor="@color/white"app:mock_showDiagonals="true"/><androidx.constraintlayout.utils.widget.MockViewandroid:id="@+id/login"android:layout_width="200dp"android:layout_height="40dp"android:layout_marginTop="30dp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@id/background"app:mock_diagonalsColor="#2196F3"app:mock_label="登录"app:mock_showDiagonals="true"/><androidx.constraintlayout.utils.widget.MockViewandroid:id="@+id/register"android:layout_width="200dp"android:layout_height="40dp"android:layout_marginTop="30dp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@id/login"app:mock_diagonalsColor="#2196F3"app:mock_label="注册"app:mock_showDiagonals="true"/>预览图:
MockView作为辅助设计的控件,它不能设置事件而且正式发布项目前建议要移除MockView,保持布局干净。
4.参考资料
- Developer-ConstraintLayout:https://developer.android.google.cn/reference/androidx/constraintlayout/widget/ConstraintLayout
- ConstraintLayout历史版本:https://developer.android.google.cn/jetpack/androidx/releases/constraintlayout?hl=zh_cn
- ImageFilterView:https://developer.android.google.cn/reference/kotlin/androidx/constraintlayout/utils/widget/ImageFilterView?hl=en
- ImageFilterButton:https://developer.android.google.cn/reference/androidx/constraintlayout/utils/widget/ImageFilterButton?hl=en
- MockView:https://developer.android.google.cn/reference/kotlin/androidx/constraintlayout/utils/widget/MockView?hl=en