Блог переїхав на HUGO . Нова адреса сайту https://sheremetat.dev
В статье описан небольшой пример того, как сделать кнопки нестандартной формы в Android приложении. Например, это могут быть овальные кнопки или кнопки в виде дуг. Пример интерфейса такой задачи изображен на рисунке.Разместив кнопки таким образом они “перекроют” друг друга и в области перекрытия, нажав на одну кнопку, можно выполнить действие другой кнопки. Проблема также в том, что нажатие на кнопке будет срабатывать за пределами области кнопки. Красные линии на рисунке показывают реальные контуры кнопки, а заштрихованная область - это область перекрытия кнопок. В центре круга и за его пределами (на белом фоне) нажатие на кнопке не должно срабатывать.
Для решение этой задачи мы сделаем следующее:
- Выделим Touch Area для каждой кнопки.
- Создадим кнопку, которая сможет управлять своей Touch Area.
- Проверим работоспособность созданной кнопки.
Создание Touch Area.
И так, начнем. Допустим, на надо реализовать интерфейс изображенный на рисунке выше. У каждой кнопки область срабатывания выделена черной рамкой.
<resources> <array name="touch_area_btntop"> <item>90 18 73 22</item> <item>58 33 135 34</item> <item>44 48 45 38</item> <item>167 48 45 38</item> </array> <array name="touch_area_btnleft"> <item>25 22 49 69</item> <item>45 82 45 42</item> <item>72 94 51 53</item> </array> <array name="touch_area_btnright"> <item>55 22 46 71</item> <item>58 33 48 34</item> <item>5 81 47 51</item> </array> </resources>
На этом этапе подготовительную работу можно считать завершенной. Переходим к самому интересному.
Создание кнопки.
Устанавливать Touch Area кнопке мы будем с помощю атрибутов в XML файле:
toucharea:toucharea="@array/touch_area_btntop"
Для этого создадим новый аттрибут и опишем его в arrts.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="TouchAreaButton"> <attr name="toucharea" format="string"/> </declare-styleable> </resources>
Теперь создадим свою кнопку. Она должна уметь прочитать атрибут Touch Area, создать эту область на кнопке и следить за тем, попало ли касание в эту область. Если касание не пришлось на область - не выполнять никаких действий с этой кнопкой.
Ниже привожу код кнопки. Все важные момент описаны в комментариях к коду.
public class RoundButton extends Button { private Region touchRegion = new Region(); public RoundButton(Context context) { super(context); } public RoundButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initStyleButton(attrs); } public RoundButton(Context context, AttributeSet attrs) { super(context, attrs); initStyleButton(attrs); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (!touchRegion.contains((int) event.getX(), (int) event.getY())) { return false; } } return super.onTouchEvent(event); } private void initStyleButton(AttributeSet attrs) { TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.TouchAreaButton); int areaId = a.getResourceId(R.styleable.TouchAreaButton_toucharea, 0); if (areaId == 0) { return; } Resources res = getResources(); TypedArray areas = res.obtainTypedArray(areaId); for (int i = 0; i < areas.length(); i++) { String touchArea = areas.getString(i); Log.d(getClass().getCanonicalName(), "touchArea = " + touchArea); String[] data = touchArea.split(" "); if (data.length < 4) continue; // koef for convert px to dp float pxToDp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, res.getDisplayMetrics()); int x = (int)(Integer.parseInt(data[0]) * pxToDp); int y = (int)(Integer.parseInt(data[1]) * pxToDp); int width = (int)(Integer.parseInt(data[2]) * pxToDp); int height = (int)(Integer.parseInt(data[3]) * pxToDp); Rect rect = new Rect(x, y, x + width, y + height); if (i == 0) { touchRegion.set(rect); } else { touchRegion.op(rect, Op.UNION); } } } }
А вот так выглядит использование этой кнопки в приложении:
<name.sheremetat.sample.RoundButton android:id="@+id/button_top" toucharea:toucharea="@array/touch_area_btntop" android:layout_marginLeft="0dp" android:layout_marginTop="0dp" android:layout_width="250dp" android:layout_height="103dp" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:text="Up" android:textStyle="bold" android:textSize="24dp" android:background="@drawable/btn_top" />
На этом откланяюсь. Код проекта выложен на GitHub.