Android UI 布局优化
背景
最近工作需要维护一个比较旧的项目、功能也比较简单,用到的技术栈也比较旧了。项目不是很紧急,现学现卖 Kotlin 重写走起。
其中有一个功能需要选择画笔的颜色以及大小,展示的时候需要显示当前画笔的状态。看到布局文件脑子有点大,做了好多级的嵌套(可能这个项目创建之前都没有约束布局)。一个选项竟然是通过一层相对布局包含View。相对布局负责边框颜色变化,View负责内容展示。
布局嵌套过多,首先想到的就是可以用约束布局优化。想到的方案是一个选项可以通过一个ImageView 展示,通过代码设置它们的background或者src。
<RelativeLayout
android:layout_width="298.6dp"
android:layout_height="190.6dp"
android:background="@drawable/shadow_3">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="27.3dp"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/color_r_1"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="@drawable/shape_pen_color_sel">
<View
android:id="@+id/color_v_1"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerInParent="true"
android:background="@drawable/shape_pen_color" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/color_r_2"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginLeft="14.6dp"
android:background="@drawable/shape_pen_color_sel">
<View
android:id="@+id/color_v_2"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerInParent="true"
android:background="@drawable/shape_pen_color"
android:backgroundTint="@color/white" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/color_r_3"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginLeft="14.6dp"
android:background="@drawable/shape_pen_color_sel">
<View
android:id="@+id/color_v_3"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerInParent="true"
android:background="@drawable/shape_pen_color"
android:backgroundTint="@color/blue" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/color_r_4"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginLeft="14.6dp"
android:background="@drawable/shape_pen_color_sel">
<View
android:id="@+id/color_v_4"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerInParent="true"
android:backgroundTint="@color/black"
android:background="@drawable/shape_pen_color" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="99.3dp"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/size_r_1"
android:layout_width="56dp"
android:layout_height="56dp"
android:background="@drawable/shape_pen_color">
<View
android:layout_width="11dp"
android:layout_height="11dp"
android:layout_centerInParent="true"
android:background="@drawable/shape_pen_size" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/size_r_2"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginLeft="31.3dp"
android:background="@drawable/shape_pen_color">
<View
android:layout_width="19dp"
android:layout_height="19dp"
android:layout_centerInParent="true"
android:background="@drawable/shape_pen_size" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/size_r_3"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginLeft="31.3dp"
android:background="@drawable/shape_pen_color">
<View
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_centerInParent="true"
android:background="@drawable/shape_pen_size" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
优化后的布局。(约束布局真的好用)
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/group"
android:layout_width="150dp"
android:layout_height="95dp"
android:background="@drawable/shadow_3">
<ImageView
android:id="@+id/color_r_1"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginTop="14dp"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/color_r_2"
app:layout_constraintTop_toTopOf="parent"
/>
<ImageView
android:id="@+id/color_r_2"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintLeft_toRightOf="@+id/color_r_1"
app:layout_constraintRight_toLeftOf="@+id/color_r_3"
app:layout_constraintTop_toTopOf="@+id/color_r_1" />
<ImageView
android:id="@+id/color_r_3"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintLeft_toRightOf="@+id/color_r_2"
app:layout_constraintRight_toLeftOf="@+id/color_r_4"
app:layout_constraintTop_toTopOf="@+id/color_r_1" />
<ImageView
android:id="@+id/color_r_4"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintLeft_toRightOf="@+id/color_r_3"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/color_r_1" />
<ImageView
android:id="@+id/size_r_1"
android:layout_width="28dp"
android:layout_height="28dp"
android:scaleType="center"
android:layout_marginTop="50dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/size_r_2"
app:layout_constraintTop_toTopOf="parent"
/>
<ImageView
android:id="@+id/size_r_2"
android:layout_width="28dp"
android:layout_height="28dp"
android:scaleType="center"
app:layout_constraintLeft_toRightOf="@+id/size_r_1"
app:layout_constraintRight_toLeftOf="@+id/size_r_3"
app:layout_constraintTop_toTopOf="@+id/size_r_1" />
<ImageView
android:id="@+id/size_r_3"
android:layout_width="28dp"
android:layout_height="28dp"
android:scaleType="center"
app:layout_constraintLeft_toRightOf="@+id/size_r_2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@+id/size_r_1" />
</androidx.constraintlayout.widget.ConstraintLayout>
GradientDrawable在Android中便是shape标签的代码实现,利用GradientDrawable也可以创建出各种形状。我们直接在代码里面设置我们需要的 shape。设置画笔颜色ImageView直接设置background就可以了。设置画笔的大小我们可以创建一个有具体宽高的形状为圆形的 shape ,ImageView 设置此为src。创建一个背景颜色为白色、边框有颜色形状为矩形shape ,ImageView 设置此为background。
class MainActivity2 : AppCompatActivity() {
private lateinit var binding: PenTypeLayoutCopyBinding
private val color = arrayOf(
Color.parseColor("#ffffff"),
Color.parseColor("#fdd02f"),
Color.parseColor("#000000"),
Color.parseColor("#157efb")
)
private val strokeNormalColor: Int = Color.parseColor("#cccccc") //边框默认颜色
private val strokeSelectedColor: Int = Color.parseColor("#3b73b5") //边框选中颜色
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = PenTypeLayoutCopyBinding.inflate(layoutInflater)
setContentView(binding.root)
//默认选择第一个
setPenColor(0)
setPenWidth(4)
binding.colorR1.setOnClickListener {
setPenColor(0)
}
binding.colorR2.setOnClickListener {
setPenColor(1)
}
binding.colorR3.setOnClickListener {
setPenColor(2)
}
binding.colorR4.setOnClickListener {
setPenColor(3)
}
binding.sizeR1.setOnClickListener {
setPenWidth(4)
}
binding.sizeR2.setOnClickListener {
setPenWidth(5)
}
binding.sizeR3.setOnClickListener {
setPenWidth(6)
}
}
//画笔颜色是从第1个选项开始
private fun setPenColor(position: Int) {
for (i in 0 until 4) {
val drawable = GradientDrawable()
drawable.shape=GradientDrawable.RECTANGLE
drawable.setColor(color[i])
val color = if (i == position) strokeSelectedColor else strokeNormalColor
drawable.setStroke(3, color)
drawable.cornerRadius = 6.0f
binding.group.getChildAt(i).background = drawable
}
}
//画笔大小是从第五个选项开始
private fun setPenWidth(position: Int) {
for (i in 4 until binding.group.childCount) {
val drawable = GradientDrawable()
drawable.shape = GradientDrawable.OVAL
drawable.cornerRadius = 6.0f
drawable.setSize(4 * i, 4 * i)
drawable.setColor(Color.parseColor("#4a4a4a"))
val imageView = binding.group.getChildAt(i) as ImageView
imageView.setImageDrawable(drawable)
val drawable1 = GradientDrawable()
drawable1.shape=GradientDrawable.RECTANGLE
drawable1.setColor(Color.WHITE)
drawable1.cornerRadius = 6.0f
val color = if (i == position) strokeSelectedColor else strokeNormalColor
drawable1.setStroke(3, color)
imageView.background = drawable1
}
}
}
踩坑地方:ImageView 需要设置 android:scaleType="center" ,这表示在视图中居中图像,但不执行缩放。不设置这个的话ImageView 设置 src 肯能会铺满 ImageView ,得不到我们想要的效果。比如:
欢迎大家提出不同的想法、建议。