I'm trying to polish up some details about my app and I'm stuck on design of android Button widget. Up from Android 5.0 everything is fine with simple system Button, but problem starts when I start my app on lower versions - specifically 4.4.2 . System Button has no effect on click which is of course wrong UX. I'd like to avoid making multiple layouts for different android version and I think there is some way to solve this without making my own selector and using in in pre-Lollipop layouts, but I just can't find it. My Button layout looks as follows :
<Button
android:id="#+id/some_id"
android:layout_width="wrap_content"
android:layout_height="#dimen/size_48dp"
android:paddingLeft="#dimen/margin_32dp"
android:paddingRight="#dimen/margin_32dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="center"
app:backgroundTint="#color/colorAccent"
android:textColor="#color/white"
android:text="#string/some_text"/>
As i said, on all post-lollipop version it has some effect (from android 6 it's ripple, before it just changes tint) but on Kitkat id does nothing. I tried using AppCompatButton, all sort of colorControlNormal, colorButtonNormal and I don't know what in styles but to no avail. Is there some "easy" way to solve this ?
You can create styles in both styles.xmlad v21 styles.xml
Below is code snippet of v21 styles.xml
<style name="ButtonRed" parent="Theme.AppCompat">
<item name="android:colorButtonNormal">#color/primary_red</item>
<item name="android:colorControlHighlight">#color/primary_red_dark</item>
<item name="android:textColor">#color/dash_title_color_white</item>
</style>
Below is code snippet of styles.xml
<style name="ButtonRed" parent="Base.Widget.AppCompat.Button">
<item name="colorButtonNormal">#color/primary_red</item>
<item name="colorControlHighlight">#color/primary_red_dark</item>
<item name="android:textColor">#color/dash_title_color_white</item>
</style>
Then you can use these styles as theme as given below
<Button
android:layout_width="wrap_content"
android:theme="#style/ButtonRed"
android:layout_height="wrap_content"
android:text="#string/recharge"
/>
Ripple type animation will only work from lollipop onwards. Below that the button will change colour state accordingly
Animations in material design give users feedback on their actions and provide visual continuity as users interact with your app. The material theme provides some default animations for buttons and activity transitions, and Android 5.0 (API level 21) and above lets you customize these animations and create new ones:
Touch feedback
Circular Reveal
Activity transitions
Curved motion
View state changes
Touch feedback in material design provides an instantaneous visual confirmation at the point of contact when users interact with UI elements. The default touch feedback animations for buttons use the new RippleDrawable class, which transitions between different states with a ripple effect.
Verify this Page
https://developer.android.com/training/material/animations.html#Touch
ANd Also these Answers will help you
how to create ripple effect for pre-lollipop
Related
According to the documentation
A Button which supports compatible features on older versions of the
platform, including:
Allows dynamic tint of its background via the background tint methods
in ViewCompat. Allows setting of the background tint using
R.attr.backgroundTint and R.attr.backgroundTintMode. This will
automatically be used when you use Button in your layouts and the
top-level activity / dialog is provided by appcompat. You should only
need to manually use this class when writing custom views.
Now, this makes me assume that the following two buttons would look exactly the same on high level devices.
<androidx.appcompat.widget.AppCompatButton
android:text="AppCompatButton"
android:id="#+id/appcompatbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:layout_below="#id/appcompatbutton"
android:id="#+id/button"
android:layout_width="wrap_content"
android:text="Button"
android:layout_height="wrap_content" />
However, here is how it actually looks:
I ran this on the following emulator:
Galaxy Nexus, API:28 (720 x 1280 xhdpi)
And when I apply buttonStyle in my appTheme like this:
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="buttonStyle">#style/Widget.MaterialComponents.Button</item>
</style>
It changes the AppCompatButton but not the normal button like this:
(Note the slight difference in the rounded edges)
I also tried to create a custom button that both inherited from android.widget.Button and also androidx.appcompat.widget.AppCompatButton, both of these buttons show the same behaviour as using AppCompatButton in xml does. So it feels like the only outlier is Button in XML.
Question 1:
This all seems incredibly confusing according to me. Can someone clarify this as either a bug or feature?
EDIT 1
Doing debugging I found that the Button actually gets transformed into a MaterialButton, see the following:
Question 2:
Why is this transformation happening?
EDIT 2
Question 2 answer:
The transformation of Button to MaterialButton is due to the parent theme I was using.
Question 3:
How do you implement a custom button which works just like Button in xml would?
As a side note and personal opinion, also a slight repetition, this system is not only confusing but its hard to get it right and foolproof for future changes. In addition to this, the documentation is very poor. I would appreciate if an answer to this would be included as well, or at least a discussion regarding it, how to deal with it for example.
Short answers.
This all seems incredibly confusing according to me. Can someone clarify this as either a bug or feature?
They use different styles.
Why is this transformation happening?
There is an auto-inflation enabled which will replace <Button with <com.google.android.material.button.MaterialButton at runtime.
How do you implement a custom button which works just like Button in xml would?
You can customize the attributes in xml or the theme attributes.
Long answers.
They use different styles.
The default style of MaterialButton is Widget.MaterialComponents.Button.
This style inherits from Widget.AppCompat.Button but changes some attributes.
Here you can find the differences.
The main difference is here:
<item name="shapeAppearance">?attr/shapeAppearanceSmallComponent</item>
You can read more about shaping in the official doc.
If you navigate through the style you will find:
<style name="ShapeAppearance.MaterialComponents.SmallComponent">
<item name="cornerSize">#dimen/mtrl_shape_corner_size_small_component</item>
</style>
where mtrl_shape_corner_size_small_component = 4dp.
It explains the slight difference in the rounded edges.
Also you are using
<item name="buttonStyle">#style/Widget.MaterialComponents.Button</item>.
It doesn't work for the MaterialButton. You have to use:
<item name="materialButtonStyle">#style/Widget.MaterialComponents.Button</item>
The auto-inflation is here.
The MaterialComponentsViewInflater replaces some framework widgets with Material Components ones at inflation time, provided a Material Components theme is in use.
Something similar happens also with AppCompat (you can check that MaterialComponentsViewInflater extends AppCompatViewInflater).
It means that, the <Button is replaced <com.google.android.material.button.MaterialButton at runtime, if you are using a Material Theme.
There are different options. One of these is to define a custom style for buttons.
<style name="AppTheme" parent="Theme.MaterialComponents.Light">
...
<item name="materialButtonStyle">#style/MyButtonStyle</item>
</style>
<style name="MyButtonStyle" parent="Widget.MaterialComponents.Button">
<item name="cornerRadius">xxx</item>
</style>
or
<style name="MyButtonStyle" parent="Widget.MaterialComponents.Button">
<item name="shapeAppearanceOverlay">#style/SShapeAppearanceOverlay.MyApp.Button.Rounded</item>
</style>
<style name="ShapeAppearanceOverlay.MyApp.Button.Rounded" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">xxdp</item>
</style>
I changed the <Button> to <ImageButton>
Quick and short way.
Don't forget to check & change references in java/kotlin files. Compiler will alert you any way.
I am developing an app, in which I want to add the ripple effect in my recyclerview. So can anyone tell me the code to do it, and is there a way I can achieve it in pre lollipop too. If not, please suggest me code with my app can show ripple effect in lollipop and upper versions and any simple effect for pre lollipop, to show item has been tapped or clicked.
Thank you.
you can use this library by this you can add ripple effect on pre-Lolipop version too.
for example
add button in your layout file
<com.rey.material.widget.Button
style="#style/ButtonRippleStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BUTTON"
app:rd_enable="true"/>
add custom style in your style file
<style name="ButtonRippleStyle" parent="Material.Drawable.Ripple.Wave.Light">
<item name="android:background">#null</item>
<item name="rd_rippleColor">#20F15A2B</item>
</style>
Why are there no ripples on pre-Lollipop?
A lot of what allows RippleDrawable to run smoothly is Android 5.0’s
new RenderThread. To optimize for performance on previous versions of
Android, we've left RippleDrawable out for now.
http://android-developers.blogspot.com.uy/2014/10/appcompat-v21-material-design-for-pre.html
If you want for pre-lollipop, you sould use a library like:
https://github.com/balysv/material-ripple
https://github.com/traex/RippleEffect
Others libraries: https://android-arsenal.com/tag/167
For >= 21 API you only need to set in your layout:
android:background="?android:attr/selectableItemBackground"
My application uses a android.support.v7.widget.ListViewCompat and I'm trying to make the "Overscroll" effect look the same on Pre-lollipop and Lollipop.
On pre-lollipop the Overscroll has the Holo-blue color and on Lollipop and above, it uses the colorPrimary attribute.
Most related answers I find on SO are either very complicated (I think this should be a one-liner, preferable in the App theme) or "borks" the default effect on lollipop and looks wierd.
So can can I write to set the overscroll color to colorPrimary on pre-lollipop devices?
My style.xml (App Theme) file currently contains
<item name="colorPrimary">#color/my_green</item>
<item name="colorPrimaryDark">#color/my_forest</item>
<item name="colorAccent">#color/my_soil</item>
<item name="colorControlNormal">#color/my_green</item>
<item name="colorControlActivated">#color/my_forest</item>
<item name="colorControlHighlight">#color/white</item>
I also find it very strange that the colorControlHighlight color is not used when selecting items in the ListView on pre-lollipop but the default holo-orange color.
Glow is taken from R.drawable.overscroll_edge, so I guess you won't be able to replace it easily. It would be easier to replace the EdgeEffect class with custom drawable. See:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.4_r1/android/widget/EdgeEffect.java#EdgeEffect
So maybe this is what you're looking for:
Unfortunately this is something really hidden and you won't be able to get that glow without reflection. The above screenshot was taken on Gingerbread, so if you're not afraid of hacks, it's possible. The code is rather long, so I won't paste it here. You can find the implementation in ScrollView and RecyclerView classes of Carbon. There's no ListView (it's now replaced by RecyclerView), but you should be able to get that working as well. It's a copy of Lollipop's glow set as edge effect, so it works and looks like it should.
https://github.com/ZieIony/Carbon/blob/master/carbon/src/main/java/carbon/widget/RecyclerView.java
I'm developing an app for Android wearables. I want to create a layout working on both round and square screens. Therefore I'm using BoxInsetLayout.
I also want to use a CheckBox from Material Theme. Therefore I'm using a custom theme derived from Theme.AppCompat.Light.
<style name="AppTheme" parent="#style/Theme.AppCompat.Light">
The problem is that BoxInsetLayout is not working properly on round screens. I'm having the same issue as described here but the solution mentioned there is not working for me. The relevant code parts are the same except the theming part.
When I switch the theme to Theme.DeviceDefault I only get the CheckBox from Holo.
Try adding:
<item name="android:windowOverscan">true</item>
to your theme. It is necessary for dispatching insets.
I've looked around for a proper way of handling the background color of Buttons in android 5.0 and the only solution I could find was to define a style for the Button in values-21/styles.xml :
<item name="android:colorButtonNormal">#2196f3</item>
Is this the only way of coloring a button, while preserving both its design and the ripple effect ?
If yes, It would imply that I have to define a custom theme for each Button which has a different color, really ???
N.B : My question doesn't relate to backwards compatibility and AppCompat, which has already been discussed a lot.
You can use the tint option to change coloring that way, instead of making a seperate theme for each button, you would just have each tinted a different color. See here: Material Design Drawables
Yes, you have to define a separate theme with colorButtonNormal for each color. You can set theme to your Button as following:
<style name="ColorButonButton" parent="Theme.AppCompat.Light">
<item name="colorButtonNormal">#color/newColor</item>
</style>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Text"
android:theme="#style/ColorButonButton"/>