-
Bug 汇总
- merge 标签在 ConstraintLayout 中约束失效。
-
知识点
- RecyclerView 自定义 ItemDecoration
- LayoutInflater 填充界面
1. Bugs:
- 在 ConstraintLayout 布局中使用 include 添加根布局标签为 merge 的 xml 页面时,约束失效。
解决方案:
- 在被添加的页面中,移除
merge
标签。
当使用 include
标签时,系统会把 include
标签的属性运用到被添加页面到根视图上。但是 merge
标签是一个特殊的标签,它允许你在布局中有多个视图,但没有根视图。所以使用 merge
标签时,所有约束会被丢弃。
2. 知识点
1. ItemDecoration
实现自定义的 ItemDecoration,主要重写三个方法,getOffSets,onDraw、和 onDrawOver。
1.1 getItemOffSets
- 作用:
设置 ItemView 的内嵌偏移长度,每个 ItemView 外部都有一个 Rect 矩形(OutRect),默认 ItemView 在 OutRect 中的偏移为 0(重叠),通过调用 outRect 方法可以设置内部 View 的偏移量。
- 代码:
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
outRect.set(50, 50, 50, 50)
}
- 效果:
1.2 onDraw
onDraw 用于在 ItemView 上进行绘制,onDraw优先进行绘制,并被
- 作用:
为每个 ItemView 绘制,绘制图层在 ItemView 以下,如果绘制区域相重叠,会被 ItemView 遮挡。
- 代码:
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDraw(c, parent, state)
val childCount = parent.childCount
paint.color = Color.YELLOW
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
val divider = 10
val left = child.left
val top = child.top - divider
val right = child.right
val bottom = child.bottom + divider
c.drawRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat(), paint)
}
}
- 效果:
1.3 onDrawOver
- 作用:
绘制图像,并显示在 itemView 的上层。
- 代码:
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDrawOver(c, parent, state)
val childCount = parent.childCount
paint.color = Color.RED
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
val top = child.top
val left = child.right - bitmap.width
c.drawBitmap(bitmap,left.toFloat(),top.toFloat(),paint)
}
}
- 效果:
1.4 实现自定义头部并将头部保持在顶部
- 代码
package com.learnandroid.androidlibraryapp.fragments
import android.content.Context
import android.graphics.*
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.learnandroid.androidlibraryapp.R
/**
* com.learnandroid.androidlibraryapp.fragments
* Author: binguner
* Date: 2019-10-23 20:24
*/
class MyRecyclerViewDecoration(val context: Context) : RecyclerView.ItemDecoration() {
private val paint: Paint = Paint()
private val textPaint: Paint = Paint()
private var bitmap:Bitmap = BitmapFactory.decodeResource(context.resources,R.drawable.ic_account_circle_black_24dp)
private val TAG = MyRecyclerViewDecoration::class.java.simpleName
private var mIndex: Int = 0
// 设置 ItemView 的内嵌偏移长度,每个 ItemView 外部都有一个 Rect 矩形(OutRect),默认 ItemView 在 OutRect 中的偏移为 0(重叠)
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
val position = parent.getChildAdapterPosition(view)
if (position % 5 == 0) {
outRect.set(0, 50, 0, 0)
}
}
// 在子视图上设置绘制范围,并绘制内容,绘制图层在 ItemView 以下,如果绘制区域相重叠,会被遮挡
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDraw(c, parent, state)
}
// 绘制内容:绘制在图层的最上面
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDrawOver(c, parent, state)
paint.color = Color.YELLOW
textPaint.color = Color.BLACK
textPaint.textSize = 35f
val childCount = parent.childCount
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
val index = parent.getChildAdapterPosition(child)
if (index % 5 == 0) {
if (i < 5) {
if (i == 1 && child.top < 100 ) {
val divider = 50
val top = child.top - divider
val left = child.left
val bottom = child.top
val right = child.right
c.drawRect(left.toFloat(),top.toFloat(),right.toFloat(),bottom.toFloat(),paint)
c.drawText("Index is $index", left.toFloat(), child.top.toFloat() - 10, textPaint)
}else{
val divider = 50
val top = 0
val left = 0
val bottom = divider
val right = child.right
c.drawRect(left.toFloat(),top.toFloat(),right.toFloat(),bottom.toFloat(),paint)
if (i == 0) {
c.drawText("Index is ${index}", left.toFloat(), 35f, textPaint)
} else {
c.drawText("Index is ${index - 5}", left.toFloat(), 35f, textPaint)
}
}
}
if (i != 0) {
val divider = 50
val top = child.top - divider
val left = child.left
val bottom = child.top
val right = child.right
c.drawRect(left.toFloat(),top.toFloat(),right.toFloat(),bottom.toFloat(),paint)
c.drawText("Index is $index", left.toFloat(), child.top.toFloat() - 10, textPaint)
}
}
val top = child.top
val left = child.right - bitmap.width
c.drawBitmap(bitmap,left.toFloat(),top.toFloat(),paint)
if (i < 5) {
val divider = 50
val top = child.top - divider
val left = child.left
val right = child.right
val bottom = child.top
}
}
}
- 效果
2. LayoutInflater
LayoutInflater 的 infalte 方法有以下几个重载:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root)
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
第一个方法里调用第二个方法,attachToRoot 默认为 true。
- 如果 root 为 null,attachToRoot 没有意义
- 如果 root 不为 null,attachToRoot 为 true,会给当前 View 添加一个父布局(root)
- 如果 root 部位 null,arrachToRoot 为 false,会将布局文件最外层的所有 layout 属性进行设置,当该 View 被添加到父布局中,layout 属性自动生效。