For some reason, I don't want to use XML's and I just want to create my UI programmatically. I now have the issue that my views are not shown on the screen, no matter how many elements I supply. This is my screen:
I don't understand why it isn't shown. I added an extremely easy view to the parent view's context using ConstraintLayout
and I even supplied a fixed height.
Note that I am using the AndroidView
because I want to use this RecyclerView with Jetpack Compose. I don't think that this causes the issue though.
I added the code below, I also upload the project here (running the app will instantly show the problem): https://github.com/Jasperav/RecyclerView/tree/main
fun createChat(context: Context): ConstraintLayout {
val recyclerView = createRecyclerView(context)
return recyclerView
}
fun createRecyclerView(context: Context): ConstraintLayout {
val constraintLayout = createConstraintLayout(context)
val parent = applyDefaults(constraintLayout.constraintLayout, View(context), MATCH_PARENT, MATCH_PARENT)
parent.setBackgroundColor(context.getColor(R.color.yellow))
constraintLayout.fill(parent, constraintLayout.constraintLayout)
val recyclerView = applyDefaults(constraintLayout.constraintLayout, RecyclerView(context), MATCH_PARENT, MATCH_PARENT)
recyclerView.setBackgroundColor(context.getColor(R.color.purple_500))
constraintLayout.fill(recyclerView, parent)
val shapeDrawable = MaterialShapeDrawable()
shapeDrawable.fillColor = ColorStateList.valueOf(context.getColor(R.color.teal_200))
shapeDrawable.setStroke(5f, context.getColor(R.color.red))
recyclerView.background = shapeDrawable
recyclerView.adapter = ChatAdapter()
recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
return constraintLayout.constraintLayout
}
class ChatCell : View {
private val textView: TextView
constructor(parent: ViewGroup) : super(parent.context) {
println("Created")
val constraintLayout = createConstraintLayout(context)
textView = applyDefaults(constraintLayout.constraintLayout, TextView(context), MATCH_PARENT, MATCH_PARENT)
constraintLayout.constraintSet.constrainHeight(textView.id, 100)
constraintLayout.constraintSet.applyTo(constraintLayout.constraintLayout)
constraintLayout.fill(textView, constraintLayout.constraintLayout)
textView.text = "test"
textView.setBackgroundColor(context.getColor(R.color.red))
setBackgroundColor(context.getColor(R.color.red))
}
fun x() {
}
}
class ViewHolderTemp : RecyclerView.ViewHolder {
val chatCell: ChatCell
constructor(chatCell: ChatCell) : super(chatCell) {
this.chatCell = chatCell
}
}
class ChatAdapter : RecyclerView.Adapter<ViewHolderTemp>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolderTemp {
val chatCell = ChatCell(parent)
return ViewHolderTemp(chatCell)
}
override fun getItemCount() = 2
override fun onBindViewHolder(holder: ViewHolderTemp, position: Int) {
holder.chatCell.x()
}
}
class Layout(val constraintLayout: ConstraintLayout, val constraintSet: ConstraintSet)
fun createConstraintLayout(context: Context): Layout {
val c = ConstraintLayout(context).apply {
id = View.generateViewId()
layoutParams = ViewGroup.LayoutParams(
MATCH_PARENT,
MATCH_PARENT,
)
}
val set = ConstraintSet()
set.clone(c)
return Layout(c, set)
}
fun <T: View> applyDefaults(constraintLayout: ConstraintLayout, view: T, width: Int, height: Int): T {
view.id = View.generateViewId()
view.layoutParams = ConstraintLayout.LayoutParams(
width,
height,
)
constraintLayout.addView(view)
return view
}
fun Layout.fill(view: View, inView: View) {
val constraintSet = ConstraintSet()
constraintSet.clone(constraintLayout)
constraintSet.connect(view.id, ConstraintSet.LEFT, inView.id, ConstraintSet.LEFT);
constraintSet.connect(view.id, ConstraintSet.TOP, inView.id, ConstraintSet.TOP);
constraintSet.connect(view.id, ConstraintSet.RIGHT, inView.id, ConstraintSet.RIGHT);
constraintSet.connect(view.id, ConstraintSet.BOTTOM, inView.id, ConstraintSet.BOTTOM);
constraintSet.applyTo(constraintLayout)
}
@Composable
fun GreetingX() {
AndroidView(factory = { context ->
createChat(context)
})
}
@Preview(showBackground = true)
@Composable
fun DefaultPreviewX() {
RecyclverTestTheme {
GreetingX()
}
}
Your class ChatCell is not doing what you think it is. Below is a version which, I think, does what you want. I have included comments to explain what is happening.
class ChatCell(parent: ViewGroup) : ConstraintLayout(parent.context) {
private val textView: TextView
init {
// LayoutParams for ConstraintLayout within the RecyclerView
layoutParams = LayoutParams(MATCH_PARENT, WRAP_CONTENT)
// Create the TextView within the ConstraintLayout and add it to the layout.
textView = TextView(parent.context).apply {
id = View.generateViewId()
// Always use ConstraintSet.MATCH_CONSTRAINT (size = 0) with appropriate constraints
// for MATCH_PARENT within a ConstraintLayout.
layoutParams = LayoutParams(ConstraintSet.MATCH_CONSTRAINT, 100)
setBackgroundColor(context.getColor(R.color.white))
}
addView(textView)
// Now that the TextView is added to the ConstraintLayout, we can constrain it.
// Note that the TextView MUST be added to the ConstraintLayout before we create
// the ConstraintSet.
val cs = ConstraintSet()
cs.clone(this)
cs.connect(
textView.id,
ConstraintSet.START,
ConstraintSet.PARENT_ID,
ConstraintSet.START
)
cs.connect(textView.id, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END)
cs.applyTo(this)
// Our item view is now created and will be drawn appropriately within the RecyclerView.
}
// Here is where we bind the text to the item view's TextView.
fun x(text: String) {
textView.text = text
}
}
The onBindViewHolder()
function would look something like the following to work with the new code:
override fun onBindViewHolder(holder: ViewHolderTemp, position: Int) {
holder.chatCell.x("Text at position $position")
}
Here is the app on an emulator:
A better function declaration for the ChatCell custom view would be
class ChatCell @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : ConstraintLayout(context, attrs)
This would allow the class to be used in XML as well as silencing Android Studio complaining about the way the class is declared.