Android, создайте округлый настраиваемый вид с проверенными и непроверенными случаями

Мне нужно создать собственный вид изображения для выбора цвета по дизайну. Когда пользователь нажимает на круг, должен появиться внутренний белый круг с галочкой, как в примере ниже:

введите здесь описание изображения

В противном случае это должен быть просто круг с некоторым цветом (непроверенное состояние), как показано ниже:

введите здесь описание изображения

Основная проблема в том, что я не знаю, как создать селектор с внутренним кругом внутри и с возможностью программной настройки цвета.

Простую округлую форму я могу настроить, например, так:

<de.hdodenhof.circleimageview.CircleImageView
    android:id="@+id/circle_crop"
    android:layout_width="32dp"
    android:layout_height="32dp"
    android:layout_gravity="center"
    android:src="@android:color/holo_red_dark" />

Как изменить его, чтобы установить белый круг с галочкой внутри в отмеченном состоянии (когда пользователь нажимает на него)?


person Michael Abyzov    schedule 22.12.2020    source источник
comment
Вам нужно будет создать собственное представление.   -  person Onik    schedule 22.12.2020
comment
@Onik, я примерно знаю, как изменить пользовательское состояние просмотра / фон. Моя проблема в том, что я не знаю, как создать селектор для проверенного состояния с кругом внутри и возможностью изменить цвет внешнего круга.   -  person Michael Abyzov    schedule 22.12.2020


Ответы (2)


Так просто.

<сильный>1. Создать layer-list Drawable под названием icon_check

<layer-list 
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item                                           //for the round white background
        android:bottom="10dp"                       //margin, "<size>" tag doesn't work
        android:end="10dp"
        android:start="10dp"
        android:top="10dp">

        <shape 
            android:shape="oval">

            <solid 
                android:color="@color/white" />

        </shape>

    </item>

    <item
        android:drawable="@drawable/check"          //check mark from built-in asset
        android:bottom="14dp"                       //margin, extra 4dp is prefered
        android:end="14dp"
        android:start="14dp"
        android:top="14dp" />

</layer-list>

<сильный>2. Создайте selector Drawable под названием foreground_check

<selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:drawable="@drawable/icon_check"             //layer-list created above
        android:state_selected="true" />

    <item
        android:drawable="@android:color/transparent"       //key point, 【"@null" doesn't work!!】
        android:state_selected="false" />

</selector>

<сильный>3. Настройка CardView

<androidx.cardview.widget.CardView                  //【MaterialCardView doesn't work!!】
    android:id="@+id/cardView"
    android:layout_width="40dp"
    android:layout_height="40dp"
    android:foreground="@drawable/foreground_check" //apply layer-list drawable
    app:cardBackgroundColor="@color/black"
    app:cardCornerRadius="20dp" />                  //half of side length

<сильный>4. Настройка контроллера пользовательского интерфейса

cardView.setOnClickListener {
    it.isSelected = !it.isSelected
}

Результат:

введите здесь описание изображения

person Sam Chen    schedule 22.12.2020
comment
Ницца! Я хочу добиться этого эффекта с помощью свойства фона одним щелчком мыши (а не щелчком с удержанием). Является ли это возможным? - person Michael Abyzov; 22.12.2020
comment
@Michael Abyzov Это один щелчок, я не удержался, посмотрите эту полную демонстрацию: youtu.be/QMijeZ2mZUs. Поскольку галочка является элементом наложения (независимо от того, визуально это или фактически), я не рекомендую вам смешивать это с фоном CardView или ImageView, если вы это сделаете, это означает, что вам нужно создать N selector drawable для N разных цветов (поскольку невыбранное состояние, доступное для рисования, установлено внутри selector), это то, что вы хотите? - person Sam Chen; 22.12.2020
comment
Прошу прощения за невнимательность, работает, как я и хотел, и без вложенных представлений. Большое спасибо! - person Michael Abyzov; 23.12.2020

Вам нужно создать селектор для рисования для вашего изображения, например:

drawable_round_view_selector

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/drawable_round_view_selected" android:state_selected="true" />
    <item android:drawable="@drawable/drawable_round_view_unselected" android:state_selected="false" />
    <item android:drawable="@drawable/drawable_round_view_unselected" />
</selector>

drawable_round_view_selected

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item>
        <shape android:shape="oval">
            <size
                android:width="40dp"
                android:height="40dp" />
            <padding
                android:bottom="10dp"
                android:left="10dp"
                android:right="10dp"
                android:top="10dp" />
            <stroke
                android:width="1dp"
                android:color="#3383FF" />
            <solid android:color="#3383FF"/>
        </shape>
    </item>

    <item>
        <shape android:shape="oval">
            <size
                android:width="40dp"
                android:height="40dp" />
            <solid android:color="#ffffff" />
        </shape>
    </item>

    <item android:drawable="@drawable/ic_baseline_check_24" />

</layer-list>

и drawable_round_view_unselected

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <size
        android:width="40dp"
        android:height="40dp" />

    <!-- unselected button background -->
    <solid
        android:color="@color/black" />

    <stroke
        android:color="@color/gray_martini"
        android:width="1dp"/>
</shape>

После этого на вашем макете установите вид изображения, например:

 <ImageView
        android:id="@+id/roundImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:src="@drawable/drawable_round_view_selector"/>

Наконец, в вашей активности или представлении изменения фрагмента в зависимости от выбранного состояния:

binding.roundImageView.setOnClickListener {
            it.isSelected = !it.isSelected
        }

PS: меняйте цвета и размеры в зависимости от ваших требований.

person ziselos    schedule 22.12.2020
comment
ваш ответ классный, но мне нужно программно изменить сплошной цвет drawable_round_view_selected ( <solid android:color="#3383FF"/> ). Можно ли немного изменить код для достижения такого эффекта? - person Michael Abyzov; 22.12.2020
comment
Проверьте, может ли это помочь вам stackoverflow.com/a/46655922/7198727 - person ziselos; 22.12.2020