Настройка размера пользовательского представления в Android

#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 , вы сможете найти решение, которое даст вам желаемое решение, в котором вы можете использовать одно и то же пользовательское представление в разных размерах.