I have two views in a constraint layout, one custom and one a standard ImageView. I want to place the ImageView below the custom view. I'm setting app:layout_constraintTop_toBottomOf
on the ImageView attach it to the bottom of the custom view.
However, my ImageView snaps to the top of the parent layout, rather than the bottom of the custom view. This happens both in the Design view of Android Studio as well as when running the app.
How can I fix this?
activity_main.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="match_parent"
tools:context=".MainActivity">
<com.example.app.DrawCharacterView
android:id="@ id/drawCharacterView"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@ id/imageView"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginTop="16dp"
android:background="#F44336"
android:padding="1dp"
android:scaleType="fitCenter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@ id/drawCharacterView" />
</androidx.constraintlayout.widget.ConstraintLayout>
DrawCharacterView.kt
package com.example.app
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.util.AttributeSet
import android.view.View
import androidx.core.content.res.ResourcesCompat
class DrawCharacterView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) : View(context) {
private lateinit var extraCanvas: Canvas
private lateinit var extraBitmap: Bitmap
private val backgroundColor = ResourcesCompat.getColor(resources, R.color.black, null)
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
if (::extraBitmap.isInitialized) extraBitmap.recycle()
extraBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
extraCanvas = Canvas(extraBitmap)
extraCanvas.drawColor(backgroundColor)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawBitmap(extraBitmap, 0f, 0f, null)
}
}
CodePudding user response:
You need to pass attrs
into your View
constructor too:
To allow Android Studio to interact with your view, at a minimum you must provide a constructor that takes a Context and an AttributeSet object as parameters. This constructor allows the layout editor to create and edit an instance of your view.
That's about the Layout Editor really, but I'm assuming the important ConstraintLayout
attributes are required so that other views can define constraints on your custom view (I don't know the details about how they're resolved, but it would make sense).
Just FYI, if you start typing this:
DrawCharacterView : View
and with your cursor at the end of View
, hit Alt Enter (or whatever your suggestions shortcut is, or click the bulb icon that pops up) you can choose Add Android View constructors using '@JvmOverloads'. That will generate this:
class DrawCharacterView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr)
which saves you time, and automatically passes the attrs
and defStyleAttr
parameters / some defaults, which is generally what you want!