Android material button with progress

Android Custom Button With Centered Progress Indicator

Recently, I’ve got a simple task in a project I am working on.
I had to create a designed button with a centered progress indicator inside of it.

The button should have 3 states:

In Enabled state, it should show text while in Loading state it should show a Circular Progress Indicator (which can be native or any custom view such as Lottie animation view) and in Disabled state it should show text but grayed out.

Here is the final look according to the design!

What sounds like a simple task turned out to be not so straight forward and easy to do!
As I’ve looked for a way of how I can implement such view, I thought that I will just create a custom view that extends some Android Button class, but if you will look on the Button classes you will (or not) be surprised that those actually extends nothing else but a TextView!!
So how I can extend a View class and then add and manipulate additional Views on it?
And also, the biggest part of this of course is the styling and theming!

After all, I want to make my custom buttons to be reusable, easy to use and with different styles like rounded corners, ripple effect and any color.

When I realised that extending Button is not an option, I thought that extending a ViewGroup like a RelativeLayout or ConstraintLayout will be much better. A ViewGroup has child views inside of it, they can be manipulated and it’s easy to change their visibility and state.
I thought, if a TextView can behave as a button then then so a ViewGroup can, it’s all matter of styling and theming.
Finally I’ve chosen RelativeLayout, I like it, it’s simple and easy to work with.

First Layout First

I’ve started with designing my custom button layout, which looks like this:

As you can see, its just a simple RelativeLayout with a centered TextView and for the progress indicator I’ve chosen to use LottieAnimationView.

One important thing here, you may look on line 13 in the XML, the TextView android: textAppearance attribute which set to be
“?android:attr/textAppearanceButton”, this attribute is the one that sets buttons default text appearance right from the app theme! If we will override it in our app theme, it will effect this TextView here. We will see this further down in the styling and theming part of this article.

Show Me The Code

Now that we have the layout ready, its time to see the code that it is associated with:

Let’s go over the code and see all about it, and that is so simple.

  1. First, notice as I mentioned that the ProgressButton class extends RelativeLayout
  2. On lines 10–14 the init block, first, inflating the layout and then on lines 12–13 initialising the childs views using findViewById
  3. Next, on line 14, calling the loadAttr() method for getting styleables attributes for the button initial state! I’ve defined a few styleables so they can be set in the custom view xml. The attributes are:
  • text — Setting the button text
  • loading — For setting initial loading state from xml
  • enabled — For setting initial enabled/disabled state
  • lottieResId — For setting any lottie animation resource from xml

4. On lines 30–34, applying the initial values to the child views, and also setting the whole view enable state. Later, this enable state will change the appearance thanks to a style and selector background drawable.

Next, on lines 37–46, setLoading method for changing the button loading states! When it is loading, the TextView is GONE and the progressBar is VISIBLE, when its not loading, the TextView is VISIBLE and the progressBar is GONE.
Notice also that when it is in loading state I am setting it so it will be not clickable.

On lines 48, a method for setting the text in code, for any purposes.

Last but not the leaset, on lines 52–55 overriding the setEnabled method for setting the whole view (The parent RelativeLayout) enable state and also the enable state of the TextView, this is important as you may want to have different text colors when the button is disabled.
Thanks to the “?android:attr/textAppearanceButton” attribute I’ve mentioned earlier, we can have any text styling for different states. I will show all styling in the next sections.

Do It With Style

After complete with layout and code, all we have to do now is connect a set of styling and theming. This part is a little bit tricky, but here is how I’ve managed it.
BTW, I really encourage you to go over this article, which explains how text appearance, theming and styling works in Android

Define a Theme in style.xml

The above xml defines two attributes which will be applied as a theme to the button custom view.
As we mentioned earlier, the textAppearanceButton attribute will effect the text that is in the TextView that in the button layout.

Next, the colorControlHighlight attribute will effect the view ripple effect when clicked. This is also an attribute that comes from the app theme which we override just for this custom view.

Читайте также:  Цикл заряда батареи андроид

The textAppearance styling:

In the above xml we set the text appearance, first we define a base TextAppearance.Body.White block with the font family, text style, size and the base color.
Next, a specific TextAppearance.ProgressButton.Black block for the black button, this block inherit from the base block but overrides the android:textColor attribute, as the text color should be different when it is disabled so I defined a selector for it.

Last but not the least, the selector for the black button text color, with different color for disabled state.

What Is Your Background?

Of course, any view should have a background right?
So is our nice little custom button, the way we do it is by defining some drawable with shape and selector just we do in any other view!

First, lets define the background drawable:

Notice that the ripple color attribute is colorControlHighligh, thats right! We’ve override it in our theme! Cool!
Now, we need to define the shape and the selector:

The above three xml’s completes the view background!!

Now that we have a theme and background ready we should combine them both together! This will be done in another style block:

Notice that in the above style xml, we defined an “android:theme” attribute and gave it the theme that has been defined earlier. This will apply that theme to the view.
Next, we’ve set the “android:background” attribute with the drawable which includes the shape and the selector!

For any new color or shape, we will have to create a bunch of styling xml as described above! But when using it we should take only the last style block which combine both the theme and the background. You may look in the example in the next section!

Thats it!! Everything is ready for use!

I’ve Built It! I Want To Use It!!

All right! This is it! It’s time to use our nice little button in a Fragment or Activity. First, let’s put it in a layout!

Using the new ProgressButton is simple as just putting it in a layout and just set the style for the preferred color!

Now in our Fragment, we can use binding to access it and use it!

Summary

As you may see, such a simple looking task requires some effort to implement in the traditionally Android and View native framework. I wonder if maybe Jetpack Compose will bring new possibilities for making Android UI manipulation much easy with the ideas of Widgets and composition!

Источник

Replace ProgressDialog with a progress button in your app

Progress Button is one of the options to show non-blocking progress in the app that Google introduced in its Material Guidelines. Unfortunately, Google doesn’t provide the out of box implementation, but we can see how to implement it using existing components and moreover how to add it to your existing app without layout changes. Stay on board!

Our goal would look like that:

Well, option 1 would be to add ProgressBar to our layout, but it’s not always convenient and easy. Default buttons have some predefined paddings, and it’s not easy to align ProgressBar on the button center. What if we want to add a text later like that? Should we change the layout again on each screen?

Option 2 would be to use 3rd party components like this. One of the main disadvantages of such an approach is you lose some part of the flexibility, and for example, you can’t take advantage of the new MaterialButton by Google. It also doesn’t follow guidelines.

Option 3: We already have a solution to show progress using drawable provided by Android — AnimationDrawable. Luckily we have a ready to use progress drawable in a support-v4 package — CircularProgressDrawable. We also have a solution to show drawable along with text — SpannableString + DynamicDrawableSpan. So then just a few lines and…

It doesn’t work as expected.

  1. The animation is freezing
  2. The drawable is not aligned with the text baseline
  3. There is no padding between text and progress

Let’s try to solve the first problem. The animation is freezing because our button doesn’t know when to redraw its state. DynamicDrawableSpan doesn’t trigger button redraw by default. That means we have to do it manually. We can subscribe to AnimationDrawable animation updates and call button.invalidate() to force button call draw while the animation is active. Now animation works fine:

Now let’s align the drawable properly. To do so, we can extend ImageSpan and override getSize and draw methods. For a better understanding of what each font metrics means you can refer to great explanation by Orhan Obut.

and use new Spannable class

Let’s check the result:

You could see that “text to progress” transition is not smooth enough. We can fix it by using ObjectAnimator . I’m not going to cover this topic here though, but you can get the idea from here .

I already prepared a “ready to use” library called “ProgressButton” for you. So you don’t need to handle view lifecycle and create all this code from scratch. It also provides smooth text change animations out of the box.

Читайте также:  Веб сторе для андроид

That’s all guys. Thanks for your time. You can read my next article here . Please press “Clap” if you find this useful so it would encourage me for the next post 🙂

Источник

Android material button with progress

Buttons allow users to take actions, and make choices, with a single tap.

Contents

Before you can use Material buttons, you need to add a dependency to the Material Components for Android library. For more information, go to the Getting started page.

Note: is auto-inflated as via MaterialComponentsViewInflater when using a Theme.Material3.* theme.

Making buttons accessible

Buttons support content labeling for accessibility and are readable by most screen readers, such as TalkBack. Text rendered in buttons is automatically provided to accessibility services. Additional content labels are usually unnecessary.

For more information on content labels, go to the Android accessibility help guide.

Toggle button is an additional pattern using a segmented container or icon.

Elevated buttons are essentially outlined buttons with a shadow. To prevent shadow creep, only use them when absolutely necessary, such as when the button requires visual separation from a patterned background.

Elevated button examples

API and source code:

The following example shows an elevated button with a text label.

Adding an icon to an elevated button

The following example shows an elevated button with an icon.

Anatomy and key properties

An elevated button has a text label, a stroked container and an optional icon.

Text label attributes

Element Attribute Related method(s) Default value
Text label android:text setText
getText
null
Color android:textColor setTextColor
getTextColor
?attr/colorOnSurface (see all states)
Typography android:textAppearance setTextAppearance ?attr/textAppearanceLabelLarge
Element Attribute Related method(s) Default value
Color app:backgroundTint setBackgroundColor
setBackgroundTintList
getBackgroundTintList
?attr/colorSurface (see all states)
Stroke color app:strokeColor setStrokeColor
setStrokeColorResource
getStrokeColor
null
Stroke width app:strokeWidth setStrokeWidth
setStrokeWidthResource
getStrokeWidth
0dp
Shape app:shapeAppearance setShapeAppearanceModel
getShapeAppearanceModel
?attr/shapeAppearanceSmallComponent
Elevation app:elevation setElevation
getElevation
1dp
Ripple color app:rippleColor setRippleColor
setRippleColorResource
getRippleColor
?attr/colorOnSurface at 16% opacity (see all states)
Element Attribute Related method(s) Default value
Icon app:icon setIcon
setIconResource
getIcon
null
Color app:iconTint setIconTint
setIconTintResource
getIconTint
?attr/colorOnSurface (see all states)
Size app:iconSize setIconSize
getIconSize
wrap_content
Gravity (position relative to text label) app:iconGravity setIconGravity
getIconGravity
start
Padding (space between icon and text label) app:iconPadding setIconPadding
getIconPadding
8dp
Element Style
Default style Widget.Material3.Button.ElevatedButton
Icon style Widget.Material3.Button.ElevatedButton.Icon

See the full list of styles and attrs.

Filled button’s contrasting surface color makes it the most prominent button after the FAB. It’s used for final or unblocking actions in a flow.

Note The filled button is the default style if the style is not set.

Filled button examples

API and source code:

The following example shows a filled button with a text label and a filled container.

Note: Since this is the default type, you don’t need to specify a style tag as long as you are using a Material Components Theme. If not, set the style to @style/Widget.Material3.Button .

Adding an icon to a filled button

The following example shows a filled button with an icon.

Anatomy and key properties

A filled button has a text label, a filled container and an optional icon.

Text label attributes

Element Attribute Related method(s) Default value
Text label android:text setText
getText
null
Color android:textColor setTextColor
getTextColor
?attr/colorOnPrimary (see all states)
Typography android:textAppearance setTextAppearance ?attr/textAppearanceLabelLarge
Element Attribute Related method(s) Default value
Color app:backgroundTint setBackgroundColor
setBackgroundTintList
getBackgroundTintList
?attr/colorPrimary (see all states)
Stroke color app:strokeColor setStrokeColor
setStrokeColorResource
getStrokeColor
null
Stroke width app:strokeWidth setStrokeWidth
setStrokeWidthResource
getStrokeWidth
0dp
Shape app:shapeAppearance setShapeAppearanceModel
getShapeAppearanceModel
?attr/shapeAppearanceSmallComponent
Elevation app:elevation setElevation
getElevation
2dp
Ripple color app:rippleColor setRippleColor
setRippleColorResource
getRippleColor
?attr/colorOnPrimary at 16% opacity (see all states)
Element Attribute Related method(s) Default value
Icon app:icon setIcon
setIconResource
getIcon
null
Color app:iconTint setIconTint
setIconTintResource
getIconTint
?attr/colorOnPrimary (see all states)
Size app:iconSize setIconSize
getIconSize
wrap_content
Gravity (position relative to text label) app:iconGravity setIconGravity
getIconGravity
start
Padding (space between icon and text label) app:iconPadding setIconPadding
getIconPadding
8dp
Element Style
Default style Widget.Material3.Button
Icon style Widget.Material3.Button.Icon
Unelevated style Widget.Material3.Button.UnelevatedButton
Unelevated icon style Widget.Material3.Button.UnelevatedButton.Icon

Default style theme attribute: ?attr/materialButtonStyle

See the full list of styles and attrs.

Filled tonal button

Filled tonal buttons have a lighter background color and darker label color, making them less visually prominent than a regular filled button. They’re still used for final or unblocking actions in a flow, but may be better when these actions don’t require quite so much emphasis.

Filled tonal button examples

API and source code:

The following example shows a filled tonal button with a text label and a filled container.

Adding an icon to a filled tonal button

The following example shows a filled tonal button with an icon.

Anatomy and key properties

A filled tonal button has a text label, a filled container and an optional icon.

Text label attributes

Element Attribute Related method(s) Default value
Text label android:text setText
getText
null
Color android:textColor setTextColor
getTextColor
?attr/colorOnSecondaryContainer (see all states)
Typography android:textAppearance setTextAppearance ?attr/textAppearanceLabelLarge
Element Attribute Related method(s) Default value
Color app:backgroundTint setBackgroundColor
setBackgroundTintList
getBackgroundTintList
?attr/colorSecondaryContainer (see all states)
Stroke color app:strokeColor setStrokeColor
setStrokeColorResource
getStrokeColor
null
Stroke width app:strokeWidth setStrokeWidth
setStrokeWidthResource
getStrokeWidth
0dp
Shape app:shapeAppearance setShapeAppearanceModel
getShapeAppearanceModel
?attr/shapeAppearanceSmallComponent
Elevation app:elevation setElevation
getElevation
2dp
Ripple color app:rippleColor setRippleColor
setRippleColorResource
getRippleColor
?attr/colorOnSecondaryContainer at 16% opacity (see all states)
Element Attribute Related method(s) Default value
Icon app:icon setIcon
setIconResource
getIcon
null
Color app:iconTint setIconTint
setIconTintResource
getIconTint
?attr/colorOnSecondaryContainer (see all states)
Size app:iconSize setIconSize
getIconSize
wrap_content
Gravity (position relative to text label) app:iconGravity setIconGravity
getIconGravity
start
Padding (space between icon and text label) app:iconPadding setIconPadding
getIconPadding
8dp
Element Style
Default style Widget.Material3.Button.TonalButton
Icon style Widget.Material3.Button.TonalButton.Icon

See the full list of styles and attrs.

Outlined buttons are for actions that need attention but aren’t the primary action, such as “See all” or “Add to cart.” This is also the button used to give someone the opportunity to change their mind or escape a flow.

Outlined button examples

API and source code:

The following example shows an outlined button with a text label and stroked container.

Adding an icon to an outlined button

The following example shows an outlined button with an icon.

Anatomy and key properties

An outlined button has a text label, a stroked container and an optional icon.

Text label attributes

Element Attribute Related method(s) Default value
Text label android:text setText
getText
null
Color android:textColor setTextColor
getTextColor
?attr/colorOnSurface (see all states)
Typography android:textAppearance setTextAppearance ?attr/textAppearanceLabelLarge
Element Attribute Related method(s) Default value
Color app:backgroundTint setBackgroundColor
setBackgroundTintList
getBackgroundTintList
@android:color/transparent (see all states)
Stroke color app:strokeColor setStrokeColor
setStrokeColorResource
getStrokeColor
?attr/colorOnSurface at 12% opacity (see all states)
Stroke width app:strokeWidth setStrokeWidth
setStrokeWidthResource
getStrokeWidth
1dp
Shape app:shapeAppearance setShapeAppearanceModel
getShapeAppearanceModel
?attr/shapeAppearanceSmallComponent
Elevation app:elevation setElevation
getElevation
0dp
Ripple color app:rippleColor setRippleColor
setRippleColorResource
getRippleColor
?attr/colorOnSurface at 16% opacity (see all states)
Element Attribute Related method(s) Default value
Icon app:icon setIcon
setIconResource
getIcon
null
Color app:iconTint setIconTint
setIconTintResource
getIconTint
?attr/colorOnSurface (see all states)
Size app:iconSize setIconSize
getIconSize
wrap_content
Gravity (position relative to text label) app:iconGravity setIconGravity
getIconGravity
start
Padding (space between icon and text label) app:iconPadding setIconPadding
getIconPadding
8dp
Element Style
Default style Widget.Material3.Button.OutlinedButton
Icon style Widget.Material3.Button.OutlinedButton.Icon

Default style theme attribute: ?attr/materialButtonOutlinedStyle

See the full list of styles and attrs.

Text buttons have less visual prominence, so should be used for low emphasis actions, such as when presenting multiple options.

Text button examples

API and source code:

The following example shows a text button with a text label.

Adding an icon to a text button

The following example shows a text button with an icon.

Anatomy and key properties

A text button has a text label, a transparent container and an optional icon.

Text label attributes

Element Attribute Related method(s) Default value
Text label android:text setText
getText
null
Color android:textColor setTextColor
getTextColor
?attr/colorOnSurface (see all states)
Typography android:textAppearance setTextAppearance ?attr/textAppearanceLabelLarge
Element Attribute Related method(s) Default value
Color app:backgroundTint setBackgroundColor
setBackgroundTintList
getBackgroundTintList
@android:color/transparent (see all states)
Stroke color app:strokeColor setStrokeColor
setStrokeColorResource
getStrokeColor
null
Stroke width app:strokeWidth setStrokeWidth
setStrokeWidthResource
getStrokeWidth
0dp
Shape app:shapeAppearance setShapeAppearanceModel
getShapeAppearanceModel
?attr/shapeAppearanceSmallComponent
Elevation app:elevation setElevation
getElevation
0dp
Ripple color app:rippleColor setRippleColor
setRippleColorResource
getRippleColor
?attr/colorOnSurface at 16% opacity (see all states)
Element Attribute Related method(s) Default value
Icon app:icon setIcon
setIconResource
getIcon
null
Color app:iconTint setIconTint
setIconTintResource
getIconTint
?attr/colorOnSurface (see all states)
Size app:iconSize setIconSize
getIconSize
wrap_content
Gravity (position relative to text label) app:iconGravity setIconGravity
getIconGravity
start
Padding (space between icon and text label) app:iconPadding setIconPadding
getIconPadding
8dp
Element Style
Default style Widget.Material3.Button.TextButton
Icon style Widget.Material3.Button.TextButton.Icon
Full Width Buttons Widget.Material3.Button.TextButton.Dialog.FullWidth

Default style theme attribute: ?attr/borderlessButtonStyle

See the full list of styles and attrs.

Toggle buttons can be used to select from a group of choices.

There are two types of toggle buttons:

To emphasize groups of related toggle buttons, a group should share a common container.

Toggle button examples

API and source code:

The following example shows a toggle button with three buttons that have text labels.

Implementing an icon-only toggle button

The following example shows a toggle button with three buttons that have icons.

Anatomy and key properties

A toggle button has a shared stroked container, icons and/or text labels.

Element Attribute Related method(s) Default value
Single selection app:singleSelection setSingleSelection
isSingleSelection
false
Selection required app:selectionRequired setSelectionRequired
isSelectionRequired
false
Element Style
Default style Widget.Material3.MaterialButtonToggleGroup

Default style theme attribute: ?attr/materialButtonToggleGroupStyle

See the full list of styles and attrs.

Icons can be used as toggle buttons when they allow selection, or deselection, of a single choice, such as marking an item as a favorite.

API and source code:

Note The CheckBox API is just one of several inputs that can implement the icon button. See other selection controls for more details.

The following example shows an icon that can be used independently or in items of a RecyclerView .

Buttons support Material Theming and can be customized in terms of color, typography and shape.

Button theming example

API and source code:

The following example shows text, outlined and filled button types with Material Theming.

Implementing button theming

Use theme attributes and styles in res/values/styles.xml to add the theme to all buttons. This affects other components:

Use default style theme attributes, styles and theme overlays. This adds the theme to all buttons but does not affect other components:

Use one of the styles in the layout. That will affect only this button:

Источник

Читайте также:  Настройка размера значков андроид
Оцените статью