我的 RecyclerView 元素中最后一个元素上方和下方的边距不正确
Margins above and below the last element in my RecyclerView element incorrect
问题:如果ImageView是VISIBLE而fragment_list_element_content
TextView只有几行文字,上下边距fragment_list_element_text_view_group
太大.如果 ImageView 消失并且 fragment_list_element_content
TextView 有很多行文本,fragment_list_element_text_view_group
上方和下方的边距太小。
xml 我有问题的布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns: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:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/fragment_list_element_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/roundrect_fragment_list_element_background"
android:elevation="@dimen/fragment_list_element_background_elevation"
android:layout_marginTop="@dimen/fragment_list_element_background_margin_top"
android:layout_marginStart="@dimen/fragment_list_element_background_margin_start"
android:layout_marginEnd="@dimen/fragment_list_element_background_margin_end"
android:layout_marginBottom="@dimen/fragment_list_element_background_margin_bottom"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<ImageView
android:id="@+id/fragment_list_element_image_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/placeholder_image"
android:contentDescription="@string/fragment_list_element_image_view_content_description"
android:adjustViewBounds="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/fragment_list_element_text_view_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/fragment_list_element_textviews_margin_top"
android:layout_marginStart="@dimen/fragment_list_element_textviews_margin_start"
android:layout_marginEnd="@dimen/fragment_list_element_textviews_margin_end"
android:layout_marginBottom="@dimen/fragment_list_element_textviews_margin_bottom"
app:layout_constraintTop_toBottomOf="@id/fragment_list_element_image_view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<TextView
android:id="@+id/fragment_list_element_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/default_date_string"
android:textSize="@dimen/fragment_list_element_date_font_size"
android:textColor="@color/font_color_grey"
android:textAllCaps="true"
android:maxLines="1"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/fragment_list_element_title" />
<TextView
android:id="@+id/fragment_list_element_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/default_text"
android:textSize="@dimen/fragment_list_element_title_font_size"
android:textColor="@color/font_color_black"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/fragment_list_element_date"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/fragment_list_element_content" />
<TextView
android:id="@+id/fragment_list_element_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/default_text"
android:textSize="@dimen/fragment_list_element_content_font_size"
android:textColor="@color/font_color_grey"
app:layout_constraintTop_toBottomOf="@id/fragment_list_element_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
inflation 我的 RecyclerViewAdapter 中的布局:
import android.annotation.SuppressLint
import android.os.Build
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
import my.project.R
import java.text.SimpleDateFormat
class MyListAdapter(private val elementList: List<Element>)
: RecyclerView.Adapter<MyListAdapter.ViewHolder>() {
class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
val background: ConstraintLayout = view.findViewById(R.id.news_list_element_background)
val imageView: ImageView = view.findViewById(R.id.news_list_element_image_view)
val date: TextView = view.findViewById(R.id.news_list_element_date)
val title: TextView = view.findViewById(R.id.news_list_element_title)
val content: TextView = view.findViewById(R.id.news_list_element_content)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(
R.layout.fragment_list_element,
parent,
false
)
return ViewHolder(itemView)
}
@SuppressLint("SimpleDateFormat")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val element = elementList[position]
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
holder.background.clipToOutline = true
}
if (element.thumbnail != null) {
holder.imageView.setImageBitmap(element.thumbnail)
holder.imageView.visibility = View.VISIBLE
} else {
holder.imageView.visibility = View.GONE
}
holder.date.text = SimpleDateFormat("dd. MMMM yyyy").format(element.date)
holder.title.text = element.title
holder.content.text = element.content
}
override fun getItemCount(): Int {
return elementList.size
}
}
直接在带有 android:layout_height="wrap_content"
的元素中使用带有 android:layout_height="match_parent"
的布局似乎会导致此问题。
为什么这不会产生构建错误,在 inflation 期间抛出 RuntimeException 或者至少显示 Lint 警告对我来说是个谜。
问题:如果ImageView是VISIBLE而fragment_list_element_content
TextView只有几行文字,上下边距fragment_list_element_text_view_group
太大.如果 ImageView 消失并且 fragment_list_element_content
TextView 有很多行文本,fragment_list_element_text_view_group
上方和下方的边距太小。
xml 我有问题的布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns: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:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/fragment_list_element_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/roundrect_fragment_list_element_background"
android:elevation="@dimen/fragment_list_element_background_elevation"
android:layout_marginTop="@dimen/fragment_list_element_background_margin_top"
android:layout_marginStart="@dimen/fragment_list_element_background_margin_start"
android:layout_marginEnd="@dimen/fragment_list_element_background_margin_end"
android:layout_marginBottom="@dimen/fragment_list_element_background_margin_bottom"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<ImageView
android:id="@+id/fragment_list_element_image_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/placeholder_image"
android:contentDescription="@string/fragment_list_element_image_view_content_description"
android:adjustViewBounds="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/fragment_list_element_text_view_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/fragment_list_element_textviews_margin_top"
android:layout_marginStart="@dimen/fragment_list_element_textviews_margin_start"
android:layout_marginEnd="@dimen/fragment_list_element_textviews_margin_end"
android:layout_marginBottom="@dimen/fragment_list_element_textviews_margin_bottom"
app:layout_constraintTop_toBottomOf="@id/fragment_list_element_image_view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<TextView
android:id="@+id/fragment_list_element_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/default_date_string"
android:textSize="@dimen/fragment_list_element_date_font_size"
android:textColor="@color/font_color_grey"
android:textAllCaps="true"
android:maxLines="1"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/fragment_list_element_title" />
<TextView
android:id="@+id/fragment_list_element_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/default_text"
android:textSize="@dimen/fragment_list_element_title_font_size"
android:textColor="@color/font_color_black"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/fragment_list_element_date"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/fragment_list_element_content" />
<TextView
android:id="@+id/fragment_list_element_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/default_text"
android:textSize="@dimen/fragment_list_element_content_font_size"
android:textColor="@color/font_color_grey"
app:layout_constraintTop_toBottomOf="@id/fragment_list_element_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
inflation 我的 RecyclerViewAdapter 中的布局:
import android.annotation.SuppressLint
import android.os.Build
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
import my.project.R
import java.text.SimpleDateFormat
class MyListAdapter(private val elementList: List<Element>)
: RecyclerView.Adapter<MyListAdapter.ViewHolder>() {
class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
val background: ConstraintLayout = view.findViewById(R.id.news_list_element_background)
val imageView: ImageView = view.findViewById(R.id.news_list_element_image_view)
val date: TextView = view.findViewById(R.id.news_list_element_date)
val title: TextView = view.findViewById(R.id.news_list_element_title)
val content: TextView = view.findViewById(R.id.news_list_element_content)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(
R.layout.fragment_list_element,
parent,
false
)
return ViewHolder(itemView)
}
@SuppressLint("SimpleDateFormat")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val element = elementList[position]
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
holder.background.clipToOutline = true
}
if (element.thumbnail != null) {
holder.imageView.setImageBitmap(element.thumbnail)
holder.imageView.visibility = View.VISIBLE
} else {
holder.imageView.visibility = View.GONE
}
holder.date.text = SimpleDateFormat("dd. MMMM yyyy").format(element.date)
holder.title.text = element.title
holder.content.text = element.content
}
override fun getItemCount(): Int {
return elementList.size
}
}
直接在带有 android:layout_height="wrap_content"
的元素中使用带有 android:layout_height="match_parent"
的布局似乎会导致此问题。
为什么这不会产生构建错误,在 inflation 期间抛出 RuntimeException 或者至少显示 Lint 警告对我来说是个谜。