Как правильно рисовать экземпляры Android FloatingActionButton, которые являются частью ViewGroup - PullRequest
1 голос
/ 04 июля 2019

Я пытаюсь создать пользовательское представление Android, которое состоит из нескольких экземпляров FloatingActionButton (пространство имен android.support.design.widget), которые расположены по кругу.

Для этого я создаю новое представление, которое наследуется от ViewGroup. Код выглядит следующим образом:

package myapp;

import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ImageView;

import myapp.R;


public class ButtonOverlayView extends ViewGroup
{
  private final float _radius = 200.0f;
  private int _desiredSize;


  public ButtonOverlayView(Context context)
  {
    super(context);
    initializeViewGroup(context);
  }


  public ButtonOverlayView(Context context, AttributeSet attrs)
  {
    super(context, attrs);
    initializeViewGroup(context);
  }


  public ButtonOverlayView(Context context, AttributeSet attrs, int defStyle)
  {
    super(context, attrs, defStyle);
    initializeViewGroup(context);
  }


  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
  {
    _desiredSize = 600;
    measureChildren(widthMeasureSpec, heightMeasureSpec);
    setMeasuredDimension(_desiredSize, _desiredSize);
  }


  @Override
  protected void onLayout(boolean b, int i, int i1, int i2, int i3)
  {
    layoutChildren();
  }


  private void initializeViewGroup(Context context)
  {
    createChildren(context, getIconIdentifiers(), getColorIdentifiers());
  }


  private void createChildren(Context context, int[] iconIdentifiers, int[] colorIdentifiers)
  {
    for(int i = 0; i < iconIdentifiers.length; i++)
    {
      final FloatingActionButton button = new FloatingActionButton(context);
      button.setImageResource(iconIdentifiers[i]);
      button.setSize(FloatingActionButton.SIZE_NORMAL);
      button.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
      button.setBackgroundTintList(ColorStateList.valueOf(colorIdentifiers[i]));
      button.setClickable(true);
      addView(button);
    }
  }


  private void layoutChildren()
  {
    int buttonCount      = getChildCount();
    int center           = _desiredSize / 2;
    float angle          = 0.0f;
    float angleIncrement = 360.0f / (buttonCount - 1);

    FloatingActionButton button = (FloatingActionButton)getChildAt(0);
    int halfWidth  = button.getMeasuredWidth()  / 2;
    int halfHeight = button.getMeasuredHeight() / 2;
    button.layout(center - halfWidth, center - halfHeight, center + halfWidth, center + halfHeight);

    for(int i = 1; i < buttonCount; i++)
    {
      button         = (FloatingActionButton)getChildAt(i);
      halfWidth      = button.getMeasuredWidth() / 2;
      halfHeight     = button.getMeasuredHeight() / 2;
      double radians = Math.toRadians(angle);
      int x          = (int)(Math.cos(radians) * _radius) + center;
      int y          = (int)(Math.sin(radians) * _radius) + center;
      button.layout(x - halfWidth, y - halfHeight, x + halfWidth, y + halfHeight);
      angle += angleIncrement;
    }
  }


  private int[] getIconIdentifiers()
  {
    final TypedArray icons = getResources().obtainTypedArray(R.array.icons);
    int[] iconIdentifiers  = new int[icons.length()];

    try
    {
      for(int i = 0; i < icons.length(); i++)
      {
        iconIdentifiers[i] = icons.getResourceId(i, -1);
      }
    }

    finally
    {
      icons.recycle();
    }

    return iconIdentifiers;
  }


  private int[] getColorIdentifiers()
  {
    final TypedArray colors = getResources().obtainTypedArray(R.array.colors);
    int[] colorIdentifiers  = new int[colors.length()];

    try
    {
      for(int i = 0; i < colors.length(); i++)
      {
        colorIdentifiers[i] = colors.getResourceId(i, -1);
      }
    }

    finally
    {
      colors.recycle();
    }

    return colorIdentifiers;
  }
}

Значки и цвета для FloatingActionButton предоставляются в отдельном XML-файле со следующим содержанием:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <array name="icons">
    <item>@android:drawable/ic_delete</item>
    <item>@android:drawable/ic_input_add</item>
    <item>@android:drawable/ic_menu_call</item>
    <item>@android:drawable/ic_delete</item>
    <item>@android:drawable/ic_input_add</item>
    <item>@android:drawable/ic_menu_call</item>
    <item>@android:drawable/ic_delete</item>
  </array>
  <array name="colors">
    <item>@color/colorPrimary</item>
    <item>@color/colorPrimary</item>
    <item>@color/colorPrimary</item>
    <item>@color/colorPrimary</item>
    <item>@color/colorPrimary</item>
    <item>@color/colorPrimary</item>
    <item>@color/colorAccent2</item>
  </array>
</resources>

Технически все это работает, то есть компилируется и отображается при интеграции в приложение Android. Однако при визуализации экземпляры FloatingActionButton выглядят "странно".

Следующие скриншоты иллюстрируют, что я имею в виду под «странным»:

Телефон 1 (Android 8.1):

enter image description here

На левом скриншоте показаны все кнопки в незажатом состоянии, в то время как на правом скриншоте нажата нижняя правая кнопка.

Телефон 2 (Android 9):

enter image description here

То же, что и выше, слева - состояние без щелчка, справа - нажатие правой нижней кнопки.

У кого-нибудь есть объяснение, почему эти кнопки выглядят "странно"? И как бы я исправить эту проблему?

Редактировать

Вдохновленный этим ТАКИМ вопросом, я более подробно рассмотрел следующие зависимости, которые я использую:

com.android.support:appcompat-v7:25.3.1
com.android.support:support-v4:25.3.1
com.android.support:support-annotations:+
com.android.support:design:25.3.1
com.android.support:support-vector-drawable:25.3.1

Поскольку это потенциально может быть ошибка в этих библиотеках, я обновил их до 28.0.0, но оптический результат остается таким же, как на скриншотах выше.

1 Ответ

0 голосов
/ 05 июля 2019

Хорошо, я нашел проблему.На скриншотах не совсем очевидно, что кнопки на самом деле прозрачные.Это происходит потому, что getColorIdentifiers неправильно извлекает цвета из XML-файла.

В результате метод setBackgroundTintList делает кнопки прозрачными.Решение состоит в том, чтобы исправить метод следующим образом:

private int[] getColorIdentifiers()
{
  return getContext().getResources().getIntArray(R.array.colors);
}
...