RecyclerView按照屏幕宽度均分子View

RecyclerView按照屏幕宽度均分子View

今天来介绍一种均分RecyclerView的方法,使单行显示的所有子View占满指定的宽度(比如屏幕宽度)吧

背景

看到Picsew酷安选择图片时能够完美地将图片按照屏幕的宽度一行显示三张图片,就觉得挺有意思的。

稍微验证下吧

为了防止子View的宽度刚好是我手机屏幕的三分之一才产生这种效果,那么先手动的修改系统最小宽度再看下效果吧。

426dp下酷安的图片选择 960dp下酷安的图片选择

而系统自带文件管理器的图片选择在不同最小宽度下效果如下

426dp下系统文件管理器的图片选择 960dp下系统文件管理器的图片选择

对比发现酷安的图片选择列表里面的子View尺寸并没有发生变化,说明并不是巧合。

方案

在创建子View的时候,将其宽度和高度设置成当前屏幕宽度的三分之一,然后向子View的容器添加合适的padding

AlbumPreviewAdapter.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
class AlbumPreviewAdapter : RecyclerView.Adapter<AlbumPreviewAdapter.AlbumPreviewHolder> {
private var pictureUrlList: ArrayList<Uri>
private val mContext: Context
private var offset = ScreenUtil.dp2px(1).toInt()
constructor(context: Context, urlList: ArrayList<Uri>) {
mContext = context
this.pictureUrlList = urlList
}
override fun getItemCount(): Int {
return pictureUrlList.size
}
override fun onBindViewHolder(holder: AlbumPreviewHolder, position: Int) {
holder.bind(position)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AlbumPreviewHolder {
val view = LayoutInflater.from(mContext)
.inflate(R.layout.layout_item_album_preview, parent, false)
val itemWidth = ScreenUtil.screenWidth() / 4
val itemLayoutParams =
ViewGroup.LayoutParams(itemWidth, itemWidth)
view.layoutParams = itemLayoutParams
return AlbumPreviewHolder(view)
}
override fun getItemViewType(position: Int): Int {
return position
}
inner class AlbumPreviewHolder : RecyclerView.ViewHolder {
private var container: RelativeLayout
var previewImg: ImageView
var selectCheckBox:CheckBox
constructor(itemView: View) : super(itemView) {
this.container = itemView.findViewById(R.id.container)
this.previewImg = itemView.findViewById(R.id.preview_img)
this.selectCheckBox = itemView.findViewById(R.id.selectCheckBox)
}
fun bind(position: Int) {
addPadding(position)
Glide.with(mContext).load(pictureUrlList[position])
.into(previewImg)
previewImg.setOnClickListener {
selectCheckBox.isChecked = !selectCheckBox.isChecked
}
}
private fun addPadding(position: Int) {
when (position % 4) {
0 -> {
// 首行不需要顶部padding
if (position < 4) {
container.setPadding(0, 0, offset, offset)
} else {
// 最左边的不需要左边距
container.setPadding(0, offset, offset, offset)
}
}
1, 2 -> {
if (position < 4) {
container.setPadding(offset, 0, offset, offset)
} else {
container.setPadding(offset, offset, offset, offset)
}
}
3 -> {
if (position < 4) {
container.setPadding(offset, 0, 0, offset)
} else {
// 最右边的不需要右边距
container.setPadding(offset, offset, 0, offset)
}
}
}
}
}
}
ScreenUtil.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class ScreenUtil {
companion object {
fun dp2px(dpValue: Float): Float {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dpValue,
Resources.getSystem().displayMetrics
)
}
fun dp2px(dpValue: Int): Float {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dpValue.toFloat(),
Resources.getSystem().displayMetrics
)
}
fun screenHeight(): Int = Resources.getSystem().displayMetrics.heightPixels
fun screenWidth(): Int = Resources.getSystem().displayMetrics.widthPixels
}
}

示例代码

MainActivity.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class MainActivity : AppCompatActivity() {
private lateinit var albumRecyclerView: RecyclerView
private lateinit var urlList: ArrayList<Uri>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
albumRecyclerView = findViewById(R.id.album_recycler_view)
urlList = getAllShownImagesPath(this)
albumRecyclerView.adapter = AlbumPreviewAdapter(this, urlList)
albumRecyclerView.layoutManager = GridLayoutManager(this, 4)
}
// 演示的查询代码,实际非常不推荐在主线程中这样做
fun getAllShownImagesPath(activity: Activity): ArrayList<Uri> {
val uriExternal: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val cursor: Cursor?
val columnIndexID: Int
val listOfAllImages: ArrayList<Uri> = ArrayList()
val projection = arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.DISPLAY_NAME
)
var imageId: Long
cursor = activity.contentResolver.query(
uriExternal, projection, MediaStore.Images.Media.MIME_TYPE + "=? or "
+ MediaStore.Images.Media.MIME_TYPE + "=?",
arrayOf("image/jpeg", "image/png"), null
)
if (cursor != null) {
columnIndexID = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
// 为了防止阻塞,这里只查询极少量的数据
while (cursor.moveToNext() && listOfAllImages.size < 16) {
if (cursor.getInt(
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)
) < 1
) {
// 过滤掉文件尺寸为0的数据
continue
}
imageId = cursor.getLong(columnIndexID)
val uriImage = Uri.withAppendedPath(uriExternal, "" + imageId)
try {
// 过滤掉文件不存在的的数据
contentResolver.openFileDescriptor(uriImage, "r")
listOfAllImages.add(uriImage)
} catch (e: IOException) {
e.printStackTrace()
}
}
cursor.close()
}
return listOfAllImages
}
}
activity_main.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/album_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
layout_item_album_preview.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@color/darcula">
<ImageView
android:id="@+id/preview_img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="Selectable Image"
android:scaleType="center" />
<CheckBox
android:id="@+id/selectCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:minWidth="0dp"
android:minHeight="0dp"
android:buttonTint="@color/redAccent"/>
</RelativeLayout>

效果展示

426dp下效果展示 963dp下效果展示
Previewin426dp Previewin963dp

的确是963dp,因为调尺寸的时候我输错了…

无视右下角的ExtendedFAB

参考链接

0