Android change button size

Анимируем изменения размеров компонента в Android

Привет, %username%! Сегодня я хотел бы поделиться с тобой способом без лишних усилий реализовать анимированное изменение размеров компонента в приложении для Android.

Я много читал про анимацию, а вот использовать в своих интерфейсах до сих пор не довелось. Хотелось опробовать наконец всякие Layout Transitions, Animators, Layout Animations и написать по этому поводу статейку, чтобы и самому лучше запомнить, и другим разжевать. Закончилось, однако, всё гораздо прозаичней — кастомным ViewGroup и ObjectAnimator’ом.

Итак, мне захотелось сделать разворачивающийся при получении фокуса EditText, как в Chrome для Android, вот такой:

Быстро прошерстив StackOverflow для определения примерного направления движения нашёл 2 варианта реализации:

  1. Использовать ScaleAnimation.
  2. Так или иначе пошагово менять размер EditText’а и запрашивать requestLayout() на каждом шаге.

Первый вариант я сразу отмёл, как минимум, потому что буквы тоже растянутся. Второй вариант звучит куда логичней, за исключением того, что каждый шаг будет полностью отрабатывать цикл onMeasure/onLayout/onDraw для всей ViewGroup, хотя необходимо изменить отображение только EditText’а. К тому-же я подозревал, что такая анимация вовсе не будет смотреться плавной.

Берём за основу второй способ и начинаем думать как уйти от вызова requestLayout() на каждом шаге. Но начнём, как положено, с малого.

Пишем ViewGroup

Начнём с того, что создадим кастомный ViewGroup для размещения наших компонентов:

Разметка содержит 3 элемента:

  1. Кнопка «Добавить таб», имеет фиксированный размер, находится слева.
  2. Кнопка «Выбрать таб», имеет фиксированный размер, находится справа.
  3. Поле для ввода URL (UrlBar, наследник от EditText’а), заполняет собой оставшееся свободное пространство.

Методы onMeasure и onLayout не представляют из себя ничего сложного — сначала меряем/располагаем кнопки, потом текстовое поле между ними.

Я делал всё это поверх другого примера, так что можно заметить присутствие лишнего кода. Например, кнопка «Добавить таб». Она отображается только при переключении в режим выбора таба, в нашем же случае она просто скрыта.

Добавляем аниматор

Сначала добавим параметр, который будет меняться во время анимации. Не будем напрямую изменять размер UrlBar’а из Animator’а, а введём переменную, которая будет отображать текущий прогресс анимации в процентах.

Мы собираемся использовать ObjectAnimator, так что нужно добавить getter и setter для нашего параметра, однако, если minSdkVersion >= 14, то, чтобы избежать рефлексии, лучше создать поле класса Property для этого.

Теперь добавим 2 inner-класса и 2 поля для старта анимации.

Не забудем зарегистрировать наш OnFocusChangeListener в initializeViews!

На этом шаге логика работы непосредственно механизма анимации закончена, осталась визуальная составляющая, но сначала зазберёмся что, зачем и почему.

  1. При изменении фокуса мы создаём ObjectAnimator, который пошагово изменяет переменную, обозначающую процент получения фокуса полем.
  2. На каждом шаге вызывается invalidate() для ViewGroup. Данный метод не приводит к переразметке, он только перерисовывает компонент.

Процесс получения фокуса UrlBar’ом будет происходить следующим образом:

  1. Скрываем все остальные элементы чтобы они не мешали отрисовке анимации (в нашем случае это кнопка переключения табов).
  2. Вызываем requestLayout() чтобы после завершения анимации реальные границы UrlBar’а совпадали с наблюдаемыми (помните, что после вызова requestLayout() методы onMeasure+onLayout могут быть вызваны с задержкой!).
  3. Начинаем пошагово менять процент выполнения анимации, вызывая на каждом шаге invalidate().
  4. Вручную на каждом шаге высчитываем границы UrlBar’а для текущего процента и перерисовываем его.
Читайте также:  Android 2 3 кэш что с ним

При потере фокуса UrlBar’ом скрывать элементы и вызывать requestLayout() нужно наоборот, в конце работы анимации. Также, введём переменную для отключения этапа разметки, и не забудем добавить изменения в методы onMeasure и onLayout:

Готовимся к рисованию

Чтобы посчитать размер UrlBar’а на каждом шаге нам нужно знать его начальный и конечный размер. Добавим 2 переменные, в которые будем запоминать этот размер и в очередной раз немного поменяем onLayout:

Рисуем!

Помните, непосредственно во время анимации реальный размер UrlBar’а не меняется, это происходит либо в начале, либо в конце анимации, а по-умолчанию отрисовывает он себя в соответствии с границами, полученными на этапе разметки. Таким образом, во время анимации реальный размер компонента больше наблюдаемого. Чтобы уменьшить в этой ситуации наблюдаемый размер при отрисовке UrlBar’а воспользуемся хитростью — будем делать clipRect на canvas’е.

Ещё одна хитрость заключается в том, чтобы убрать фон у UrlBar’а и отрисовывать его вручную.

Немножечко меняем разметку.

Вводим переменную для отрисовки фона.

И, наконец, отрисовка! Добавим в метод drawChild(Canvas, View, long) условие для UrlBar’а:

Всё готово, можно запускать и смотреть:

Заключение

Принимаясь за работу, я ожидал, что задача окажется пустяковой и я справлюсь с ней буквально за один вечер. В который раз я натыкаюсь на эти грабли. Если у вас есть другие варианты реализации или замечания к текущей — обязательно поделитесь ими в комментариях.

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

Источник

Buttons

A button consists of text or an icon (or both text and an icon) that communicates what action occurs when the user touches it.

Depending on whether you want a button with text, an icon, or both, you can create the button in your layout in three ways:

  • With text, using the Button class:
  • With an icon, using the ImageButton class:
  • With text and an icon, using the Button class with the android:drawableLeft attribute:

Key classes are the following:

Responding to Click Events

When the user clicks a button, the Button object receives an on-click event.

To define the click event handler for a button, add the android:onClick attribute to the element in your XML layout. The value for this attribute must be the name of the method you want to call in response to a click event. The Activity hosting the layout must then implement the corresponding method.

For example, here’s a layout with a button using android:onClick :

Within the Activity that hosts this layout, the following method handles the click event:

Kotlin

The method you declare in the android:onClick attribute must have a signature exactly as shown above. Specifically, the method must:

  • Be public
  • Return void
  • Define a View as its only parameter (this will be the View that was clicked)

Using an OnClickListener

You can also declare the click event handler programmatically rather than in an XML layout. This might be necessary if you instantiate the Button at runtime or you need to declare the click behavior in a Fragment subclass.

To declare the event handler programmatically, create an View.OnClickListener object and assign it to the button by calling setOnClickListener(View.OnClickListener) . For example:

Читайте также:  Аида 64 для андроида

Kotlin

Styling Your Button

The appearance of your button (background image and font) may vary from one device to another, because devices by different manufacturers often have different default styles for input controls.

You can control exactly how your controls are styled using a theme that you apply to your entire application. For instance, to ensure that all devices running Android 4.0 and higher use the Holo theme in your app, declare android:theme=»@android:style/Theme.Holo» in your manifest’s element. Also read the blog post, Holo Everywhere for information about using the Holo theme while supporting older devices.

To customize individual buttons with a different background, specify the android:background attribute with a drawable or color resource. Alternatively, you can apply a style for the button, which works in a manner similar to HTML styles to define multiple style properties such as the background, font, size, and others. For more information about applying styles, see Styles and Themes.

Borderless button

One design that can be useful is a «borderless» button. Borderless buttons resemble basic buttons except that they have no borders or background but still change appearance during different states, such as when clicked.

To create a borderless button, apply the borderlessButtonStyle style to the button. For example:

Custom background

If you want to truly redefine the appearance of your button, you can specify a custom background. Instead of supplying a simple bitmap or color, however, your background should be a state list resource that changes appearance depending on the button’s current state.

You can define the state list in an XML file that defines three different images or colors to use for the different button states.

To create a state list drawable for your button background:

    Create three bitmaps for the button background that represent the default, pressed, and focused button states.

To ensure that your images fit buttons of various sizes, create the bitmaps as Nine-patch bitmaps.

Источник

Анимируем изменения размеров компонента в Android

Привет, %username%! Сегодня я хотел бы поделиться с тобой способом без лишних усилий реализовать анимированное изменение размеров компонента в приложении для Android.

Я много читал про анимацию, а вот использовать в своих интерфейсах до сих пор не довелось. Хотелось опробовать наконец всякие Layout Transitions, Animators, Layout Animations и написать по этому поводу статейку, чтобы и самому лучше запомнить, и другим разжевать. Закончилось, однако, всё гораздо прозаичней — кастомным ViewGroup и ObjectAnimator’ом.

Итак, мне захотелось сделать разворачивающийся при получении фокуса EditText, как в Chrome для Android, вот такой:

Быстро прошерстив StackOverflow для определения примерного направления движения нашёл 2 варианта реализации:

  1. Использовать ScaleAnimation.
  2. Так или иначе пошагово менять размер EditText’а и запрашивать requestLayout() на каждом шаге.

Первый вариант я сразу отмёл, как минимум, потому что буквы тоже растянутся. Второй вариант звучит куда логичней, за исключением того, что каждый шаг будет полностью отрабатывать цикл onMeasure/onLayout/onDraw для всей ViewGroup, хотя необходимо изменить отображение только EditText’а. К тому-же я подозревал, что такая анимация вовсе не будет смотреться плавной.

Берём за основу второй способ и начинаем думать как уйти от вызова requestLayout() на каждом шаге. Но начнём, как положено, с малого.

Пишем ViewGroup

Начнём с того, что создадим кастомный ViewGroup для размещения наших компонентов:

Читайте также:  Андроид нет доступа папке system

Разметка содержит 3 элемента:

  1. Кнопка «Добавить таб», имеет фиксированный размер, находится слева.
  2. Кнопка «Выбрать таб», имеет фиксированный размер, находится справа.
  3. Поле для ввода URL (UrlBar, наследник от EditText’а), заполняет собой оставшееся свободное пространство.

Методы onMeasure и onLayout не представляют из себя ничего сложного — сначала меряем/располагаем кнопки, потом текстовое поле между ними.

Я делал всё это поверх другого примера, так что можно заметить присутствие лишнего кода. Например, кнопка «Добавить таб». Она отображается только при переключении в режим выбора таба, в нашем же случае она просто скрыта.

Добавляем аниматор

Сначала добавим параметр, который будет меняться во время анимации. Не будем напрямую изменять размер UrlBar’а из Animator’а, а введём переменную, которая будет отображать текущий прогресс анимации в процентах.

Мы собираемся использовать ObjectAnimator, так что нужно добавить getter и setter для нашего параметра, однако, если minSdkVersion >= 14, то, чтобы избежать рефлексии, лучше создать поле класса Property для этого.

Теперь добавим 2 inner-класса и 2 поля для старта анимации.

Не забудем зарегистрировать наш OnFocusChangeListener в initializeViews!

На этом шаге логика работы непосредственно механизма анимации закончена, осталась визуальная составляющая, но сначала зазберёмся что, зачем и почему.

  1. При изменении фокуса мы создаём ObjectAnimator, который пошагово изменяет переменную, обозначающую процент получения фокуса полем.
  2. На каждом шаге вызывается invalidate() для ViewGroup. Данный метод не приводит к переразметке, он только перерисовывает компонент.

Процесс получения фокуса UrlBar’ом будет происходить следующим образом:

  1. Скрываем все остальные элементы чтобы они не мешали отрисовке анимации (в нашем случае это кнопка переключения табов).
  2. Вызываем requestLayout() чтобы после завершения анимации реальные границы UrlBar’а совпадали с наблюдаемыми (помните, что после вызова requestLayout() методы onMeasure+onLayout могут быть вызваны с задержкой!).
  3. Начинаем пошагово менять процент выполнения анимации, вызывая на каждом шаге invalidate().
  4. Вручную на каждом шаге высчитываем границы UrlBar’а для текущего процента и перерисовываем его.

При потере фокуса UrlBar’ом скрывать элементы и вызывать requestLayout() нужно наоборот, в конце работы анимации. Также, введём переменную для отключения этапа разметки, и не забудем добавить изменения в методы onMeasure и onLayout:

Готовимся к рисованию

Чтобы посчитать размер UrlBar’а на каждом шаге нам нужно знать его начальный и конечный размер. Добавим 2 переменные, в которые будем запоминать этот размер и в очередной раз немного поменяем onLayout:

Рисуем!

Помните, непосредственно во время анимации реальный размер UrlBar’а не меняется, это происходит либо в начале, либо в конце анимации, а по-умолчанию отрисовывает он себя в соответствии с границами, полученными на этапе разметки. Таким образом, во время анимации реальный размер компонента больше наблюдаемого. Чтобы уменьшить в этой ситуации наблюдаемый размер при отрисовке UrlBar’а воспользуемся хитростью — будем делать clipRect на canvas’е.

Ещё одна хитрость заключается в том, чтобы убрать фон у UrlBar’а и отрисовывать его вручную.

Немножечко меняем разметку.

Вводим переменную для отрисовки фона.

И, наконец, отрисовка! Добавим в метод drawChild(Canvas, View, long) условие для UrlBar’а:

Всё готово, можно запускать и смотреть:

Заключение

Принимаясь за работу, я ожидал, что задача окажется пустяковой и я справлюсь с ней буквально за один вечер. В который раз я натыкаюсь на эти грабли. Если у вас есть другие варианты реализации или замечания к текущей — обязательно поделитесь ими в комментариях.

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

Источник

Оцените статью