Custom View — это пользовательский компонент, который вы создаете сами, чтобы реализовать уникальное поведение или внешний вид, недоступные в стандартных виджетах Android
.
- Уникальный дизайн - Когда стандартные виджеты не могут реализовать нужный вам дизайн.
- Сложная логика - Когда требуется сложная логика отрисовки или обработки событий.
- Повторное использование - Когда вы хотите создать компонент, который можно использовать в нескольких местах.
- Создайте класс, который наследуется от
View
или другого стандартного виджета (например,Button
,TextView
). - Переопределите методы для отрисовки (
onDraw
) и обработки событий (onTouchEvent
). - Добавьте атрибуты для настройки
Custom View
черезXML
. - Используйте
Custom View
вXML
-разметке или программно.
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View
class CircleView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint = Paint().apply {
color = Color.RED
isAntiAlias = true
style = Paint.Style.FILL
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val radius = (width.coerceAtMost(height) / 2).toFloat()
canvas.drawCircle(width / 2f, height / 2f, radius, paint)
}
}
<com.example.myapp.CircleView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="16dp" />
- Создайте файл атрибутов в
res
/values
/attrs.xml
. - Определите атрибуты для
Custom View
. - Используйте атрибуты в
XML
и обрабатывайте их в коде.
<declare-styleable name="CircleView">
<attr name="circleColor" format="color" />
</declare-styleable>
class CircleView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint = Paint().apply {
isAntiAlias = true
style = Paint.Style.FILL
}
init {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleView)
val circleColor = typedArray.getColor(R.styleable.CircleView_circleColor, Color.RED)
typedArray.recycle()
paint.color = circleColor
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val radius = (width.coerceAtMost(height) / 2).toFloat()
canvas.drawCircle(width / 2f, height / 2f, radius, paint)
}
}
<com.example.myapp.CircleView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="16dp"
app:circleColor="@color/blue" />
Можно переопределить метод onTouchEvent
, чтобы обрабатывать касания.
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
paint.color = Color.GREEN
invalidate() // Перерисовать View
return true
}
MotionEvent.ACTION_UP -> {
paint.color = Color.RED
invalidate() // Перерисовать View
return true
}
}
return super.onTouchEvent(event)
}
- Используйте invalidate() и postInvalidate()
invalidate()
— ПерерисовываетView
в главном потоке.postInvalidate()
— ПерерисовываетView
в фоновом потоке.
- Минимизируйте вызовы onDraw
- Избегайте сложных вычислений в onDraw.
- Используйте кэширование для часто используемых значений.
- Используйте Canvas и Paint эффективно
- Создавайте объекты Paint один раз и переиспользуйте их.
- Используйте методы Canvas для оптимизации отрисовки.
class TextProgressBar @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val backgroundPaint = Paint().apply {
color = Color.LTGRAY
style = Paint.Style.FILL
}
private val progressPaint = Paint().apply {
color = Color.BLUE
style = Paint.Style.FILL
}
private val textPaint = Paint().apply {
color = Color.WHITE
textSize = 40f
textAlign = Paint.Align.CENTER
}
var progress: Int = 50
set(value) {
field = value.coerceIn(0, 100)
invalidate()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// Отрисовка фона
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), backgroundPaint)
// Отрисовка прогресса
val progressWidth = (width * progress / 100f)
canvas.drawRect(0f, 0f, progressWidth, height.toFloat(), progressPaint)
// Отрисовка текста
val text = "$progress%"
val x = width / 2f
val y = height / 2f - (textPaint.descent() + textPaint.ascent()) / 2f
canvas.drawText(text, x, y, textPaint)
}
}
<com.example.myapp.TextProgressBar
android:layout_width="200dp"
android:layout_height="30dp"
android:layout_margin="16dp" />
Custom View — Пользовательский компонент для уникального дизайна и поведения.
- Создайте класс, наследуемый от View.
- Переопределите onDraw для отрисовки.
- Добавьте атрибуты через attrs.xml.
- Обрабатывайте события через onTouchEvent.
- Используйте
invalidate()
иpostInvalidate()
. - Минимизируйте вызовы
onDraw
.