#android #kotlin #android-layout #size #android-custom-view
#Android #котлин #android-макет #размер #android-пользовательский вид
Вопрос:
Я создал пользовательский вид для отображения скорости в Android. Моя цель состоит в том, чтобы размер пользовательского представления всегда соответствовал родительскому элементу. Подобный этому:
Я уже экспериментировал с onMeasure()
этим , но не мог понять, как заставить это работать.
Вот код моего пользовательского представления:
import android.content.Context import android.graphics.* import android.util.AttributeSet import android.view.View import androidx.core.content.ContextCompat import de.hdm.rollingchassis.R import android.graphics.RectF import android.view.View.MeasureSpec import android.graphics.Typeface import android.text.TextPaint import android.util.Log class SpeedView : View { constructor(context: Context?) : super(context) constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super( context, attrs, defStyle ) // speed arc var speedDisplaySize = 300F var trackColor = ContextCompat.getColor(context, R.color.white2) var progressColor = ContextCompat.getColor(context, R.color.white) var trackBorderWidth = 5.0F var startAngle = 120F // 90 degrees is the bottom of the circle var sweepAngle = 0F // speed font var speed = 0F var speedFontColor = ContextCompat.getColor(context, R.color.white) var speedFont = "sans-serif-light" var speedFontSize = 90F // unit font var unitFont = "sans-serif" var unitFontSize = 25.0F override fun draw(canvas: Canvas?) { super.draw(canvas) canvas?.drawPath(path(300F), paint(trackColor)) canvas?.drawPath(path(sweepAngle), paint(progressColor)) canvas?.drawText( speed.toString(), (speedDisplaySize trackBorderWidth) / 2, (speedDisplaySize trackBorderWidth) / 2 (speedFontSize / 4F), paintSpeed(speedFont, speedFontSize) ) canvas?.drawText( "KM/H", (speedDisplaySize trackBorderWidth) / 2, (speedDisplaySize trackBorderWidth) / 2 (speedFontSize / 4F) 1.5F * unitFontSize, paintSpeed(unitFont, unitFontSize) ) } private fun path(sweepAngle: Float): Path { val path = Path() var oval_start_x = trackBorderWidth / 2 var oval_start_y = trackBorderWidth / 2 var oval_end_x = oval_start_x speedDisplaySize var oval_end_y = oval_start_y speedDisplaySize val oval = RectF(oval_start_x, oval_start_y, oval_end_x, oval_end_y) path.addArc(oval, startAngle, sweepAngle) return path } private fun paint(color: Int): Paint { val paint = Paint() paint.color = color paint.strokeWidth = trackBorderWidth paint.style = Paint.Style.STROKE; return paint } private fun paintSpeed(font: String, fontSize: Float): Paint { val textPaint = TextPaint() textPaint.textSize = fontSize textPaint.textAlign = Paint.Align.CENTER textPaint.color = speedFontColor textPaint.typeface = Typeface.create(font, Typeface.NORMAL) return textPaint } }
А это файл макета:
lt;?xml version="1.0" encoding="utf-8"?gt; lt;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"gt; lt;androidx.constraintlayout.widget.ConstraintLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginStart="32dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintWidth_default="percent" app:layout_constraintWidth_percent="0.3"gt; lt;androidx.constraintlayout.widget.ConstraintLayout android:id="@ id/constraintLayout" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintHeight_default="percent" app:layout_constraintHeight_percent="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintWidth_default="percent" app:layout_constraintWidth_percent="0.5"gt; lt;androidx.constraintlayout.widget.ConstraintLayout android:id="@ id/constraintLayout2" android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="16dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintDimensionRatio="1:1" app:layout_constraintHeight_default="percent" app:layout_constraintHeight_percent="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.0"gt; lt;com.example.views.SpeedView android:id="@ id/sv" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /gt; lt;/androidx.constraintlayout.widget.ConstraintLayoutgt; lt;/androidx.constraintlayout.widget.ConstraintLayoutgt; lt;/androidx.constraintlayout.widget.ConstraintLayoutgt; lt;/androidx.constraintlayout.widget.ConstraintLayoutgt;
Я бы хотел, чтобы пользовательский вид скорости соответствовал размеру ограничения с идентификатором constraintLayout2
. Кто-нибудь знает, как это сделать?
Комментарии:
1. Похоже, что вы используете фиксированный размер для своего пользовательского представления,
speedDisplaySize
который, вероятно, ограничивает размер всего этого-есть ли какая-то особая причина, по которой вы вместо этого не используете параметры макета? Кроме того, рассматривали ли вы возможность создания этого пользовательского представления с помощью XML?2. @IvanGarza Спасибо за ваш ответ! Я использовал фиксированный размер, потому что не знал, что есть другой вариант. Я все еще новичок в Android 😉 Как еще я мог это сделать?
addArc()
вpath()
функции ожидается объект типаRectF
. ИRectF()
нужны координаты X и Y. Есть ли возможность установить эти координаты иначе, чем в пикселях?
Ответ №1:
Я думаю, что ваша проблема может быть связана с speedDisplaySize
константой, которую вы используете для построения иерархии представлений.
Я бы рекомендовал вам использовать несколько иной подход и вместо этого создать свой пользовательский интерфейс в XML, окруженный парой lt;mergegt;lt;/mergegt;
тегов, так же, как вы делаете с обычной компоновкой. Например.,
lt;merge ... tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout"gt; lt;!-- Build your layout in XML, where the 'parentTag' above specifies the root layout ViewGroup --gt; lt;/mergegt;
merge
Теги позволят вам расширить это представление XML до класса кода Java/Kotlin, расширяющего корень ViewGroup
, который вы хотите указать. Например.,
class YourCustomViewName @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr) { // super class specifies the root ViewGroup type for the XML init { // Add any customizations, read in `attrs` or do what ever you want here } }
Это решение должно сэкономить вам много кода и предоставить гораздо больше свободы при изменении внешнего вида или поведения вашего пользовательского представления.
И последнее, но не менее важное: если вы правильно построите свой XML, то есть сделаете много размеров или wrap_content
или match_parent
, вы сможете найти решение, которое даст вам желаемое решение, в котором вы можете использовать одно и то же пользовательское представление в разных размерах.