转自:Constraint Layout 2.0 several new features-2
Constraint Layout Practice and Summary-1
Constraint Layout 2.0 several new features-2
Flow
Flow是虚拟布局(virtual layout,因此不会将级别添加到布局层次结构中)。类似于一个链,可以快速的横向或纵向布局constraint_referenced_ids
里面所有的elements
,通过flow_wrapMode
可以指定三种展示方式。
- wrap none: 简单的创建一个链,所有引用的视图以一条链的方式进行布局,如果内容溢出则溢出内容不可见。
- wrap chain: 根据空间的大小创建一个或多个链,当出现溢出时,溢出的内容会自动换行,以新的一条链的方式进行布局。
- wrap aligned: 与wrap chain相似,列的元素会对齐。
// 省略width、height、textColor等代码
<TextView
android:id="@+id/tvZi"
android:text="子" />
// tvChou,tvYin,tvMao,tvChen,tvSi,tvWu,tvWei等代码同tvZi一致
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="0dp"
app:constraint_referenced_ids="tvZi,tvChou,tvYin,tvMao,tvChen,tvSi,tvWu,tvWei"
app:flow_horizontalGap="8dp"
app:flow_verticalGap="10dp"
app:flow_wrapMode="aligned" />
三种展示方式的效果(图片来自网络):
还可以配合其他属性进行不同需求的展示:
- flow_horizontalStyle = "spread|spread_inside|packed"
- flow_verticalStyle = "spread|spread_inside|packed"
- flow_horizontalBias = "float"
- flow_verticalBias = "float"
- flow_horizontalGap = "dimension"
- flow_verticalGap = "dimension"
- flow_horizontalAlign = "start|end"
- flow_verticalAlign = "top|bottom|center|baseline
Layer
作为一种新的辅助工具,可以让您在多个视图上创建一个虚拟的图层。同Flow
不同,它并不会对视图进行布局,而是对多个视图同时进行变换(transformation)操作,比如多个视图整体进行旋转(rotate)、平移(translate)或缩放(scale)操作,Layer
将会是最佳的选择。
// 部分代码省略
<androidx.constraintlayout.helper.widget.Layer
android:id="@+id/layer"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/corner_white"
app:constraint_referenced_ids="tvZi,tvChou,tvYin,tvMao"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!--子丑寅卯辰巳午未申酉戌亥-->
<TextView
android:id="@+id/tvZi"
android:text="子"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="50dp"
android:layout_marginTop="16dp" />
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_layer)
layerDemo()
}
/**
* 执行layer区域动画
*/
private fun layerDemo() {
val layer = findViewById<Layer>(R.id.layer)
val valueAnimator = ValueAnimator.ofFloat(0f, 60f, -30f, 0f, -20f, 0f, -8f, 0f)
valueAnimator.addUpdateListener(AnimatorUpdateListener { animation ->
if (null == animation.animatedValue) {
return@AnimatorUpdateListener
}
val animatedValue = animation.animatedValue.toString().toFloat()
layer.translationX = animatedValue
})
valueAnimator.duration = 800
valueAnimator.start()
}
执行效果如下,所有控件类似snack移动效果。
ConstraintHelper
Flow
和Layer
均继承自ConstraintHelper
,类属于辅助工具类,而且可以自定义实现。
1、ConstraintHelper
持有view
的引用,所以可以获取views
(getViews)对其进行操作,提供了·onLayout·前后的回调(updatePreLayout)。
以下是对view作出CircularReveal
的效果,ViewAnimationUtils
给我们提供了createCircularReveal
这个函数,
class CircularAnimationHelper @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintHelper(context, attrs, defStyleAttr) {
// updatePostLayout会在onLayout之后调用,在这里做动画
override fun updatePostLayout(container: ConstraintLayout) {
super.updatePostLayout(container)
val views = getViews(container)
views.forEach {
// 计算出中心点centerX,centerY和endRadius(半径)
val createCircularReveal = ViewAnimationUtils.createCircularReveal(it, it.width / 2,
it.height / 2, 0f,
hypot((it.height / 2).toDouble(), (it.width / 2).toDouble()).toFloat()
);
createCircularReveal.duration = 1000 + Random.nextLong(500) * Random.nextInt(5)
createCircularReveal.start()
}
}
}
2、CircularRevealHelper
可以直接在xml
里面使用,在constraint_referenced_ids
里面指定需要做动画view
。如果有其他view也有同样的需求则直接复用即可。
<TextView
android:id="@+id/tvZi"
android:text="子"
android:textColor="#ffffff"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="50dp"
android:layout_marginTop="16dp" />
<cn.edu.iflifeonlyasfirstseen.constraint.layout.CircularAnimationHelper
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="tvZi,tvChou,tvYin,tvMao" />
<cn.edu.iflifeonlyasfirstseen.constraint.layout.FlyhereAnimationHelper
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="tvMao,tvYin" />
3、执行效果,由中心向四周扩散和飞入效果
ImageFilterView
An ImageView that can display, combine and filter images. Added in 2.0
Subclass of ImageView to handle various common filtering operations
一个可以显示,合并和过滤的图像,放在utils.widget
目录中的一个View
,继承自AppCompatImageView
。
属性
Attributes | Meaning |
---|---|
altSrc | 提供src图像的替代图像以允许淡入淡出 |
saturation | 设置图像的饱和度。 0 =灰度,1 =原始,2 =超饱和 |
brightness | 设置图像的亮度。 0 =黑色,1 =原始,2 =两倍的亮度 |
warmth | 调整图像的表观色温。 1 =中性,2 =温暖,.5 =冷 |
contrast | 设置对比度。 1 =不变,0 =灰色,2 =高对比度 |
crossfade | 设置两个图像之间的当前混合。 0 = src 1 = altSrc图片 |
round | 用于实现圆角,以 dimension 为值, call the TransitionListener with this trigger id |
roundPercent | 用于实现圆角,取值在0f-1f 之间,为1f 时将形成一张圆形图片 |
overlay | 定义替换图像是在原始图像上淡入淡出还是与其交叉淡入淡出。 默认为true。对于半透明对象设置为false |
布局中添加ImageFilterView
,
// activity_image_filter.xml
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/iv_1"
android:layout_width="120dp"
android:layout_height="120dp"
app:srcCompat="@mipmap/cat" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/iv_7"
android:layout_width="120dp"
android:layout_height="120dp"
app:altSrc="@drawable/tiger"
app:srcCompat="@drawable/cat" />
<!-- Omit code... -->
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="0dp"
app:constraint_referenced_ids="iv_1,iv_2,iv_3,iv_4,iv_5,iv_6,iv_7,iv_8"
app:flow_horizontalGap="40dp"
app:flow_horizontalStyle="packed"
app:flow_verticalGap="20dp"
app:flow_wrapMode="aligned" />
<androidx.appcompat.widget.AppCompatSeekBar
android:id="@+id/seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:max="100"
android:progress="0"
app:layout_constraintBottom_toBottomOf="parent" />
通过seekbar来更改属性值演示效果。
class ImageFilterActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_image_filter)
val iv1: ImageFilterView = findViewById(R.id.iv_1)
// ...Omit code
val seekBar: SeekBar = findViewById(R.id.seekbar)
seekBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
if (fromUser) {
// 如果是用户行为触发的,才作相应操作。false为code执行。
val realProgress = (progress / 100.0).toFloat()
iv1.saturation = realProgress * 10
iv2.brightness = 1 - realProgress
iv3.warmth = realProgress * 20
iv4.contrast = realProgress * 2
iv5.round = realProgress * 100
iv6.roundPercent = realProgress
iv7.crossfade = realProgress
}
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
// TODO("not yet implemented")
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
}
执行效果
输出是最好的输入方式!