I created custom button based on a MaterialButton that is semi-transparent (primaryColorDisabled) when pressed and disabled. Now, I would like to have its ripple effect to turn the button from its primaryColor to the primaryColorDisabled instead of the MaterialButton's default highlighted color.
My colors only differ only in alpha and are defined:
<color name="primaryColor">#283593</color>
<color name="primaryColorDisabled">#A0283593</color>
To my custom button I apply the following style:
<style name="CustomButton" parent="Widget.MaterialComponents.Button">
<item name="android:background">#drawable/custom_background</item>
</style>
Below are the recursive definitions of my drawables. I removed not pertinent bits like namespace, padding, margins, etc.
#drawable/custom_background:
<selector>
<item android:state_enabled="false"
android:drawable="#drawable/custom_disabled" />
<item android:state_pressed="true"
android:drawable="#drawable/custom_disabled" />
<item android:drawable="#drawable/custom_ripple" />
</selector>
#drawable/custom_disabled:
<inset>
<shape
android:shape="rectangle"
android:tint="#color/primaryColorDisabled" >
<solid android:color="#color/primaryColor" />
</shape>
</inset>
#drawable/custom_ripple:
<ripple android:color="?attr/colorControlHighlight">
<item android:drawable="#drawable/custom_enabled" />
</ripple>
#drawable/custom_enabled:
<inset>
<shape
android:shape="rectangle" >
<solid android:color="#color/primaryColor" />
</shape>
</inset>
Now, I tried changing in #drawable/custom_ripple the color from ?attr/colorControlHighlight to my #color/primaryColorDisabled, but then when I click on my button nothing changes: no ripple and no even 'state_pressed' look. Any ideas how to achieve that?
I know how to make Material Design button with color fill:
style="#style/Widget.AppCompat.Button.Colored"
And no-bordered transparent button:
style="#style/Widget.AppCompat.Button.Borderless.Colored"
However, is there a way to make Material design bordered (transparent inside) button? Something like below?
You can also use the Material Components for Android.
Add the dependency to your build.gradle:
dependencies { implementation 'com.google.android.material:material:1.3.0' }
In this case you can use the MaterialButton in your layout file:
<com.google.android.material.button.MaterialButton
....
style="#style/Widget.MaterialComponents.Button.OutlinedButton"
app:cornerRadius=".."
app:strokeColor="#color/colorPrimary"/>
Apply the style #style/Widget.MaterialComponents.Button.OutlinedButton.
In your case use the app:cornerRadius attribute to change the size of corner radius. This will round off the corners with specified dimensions.
Use te attribute app:strokeColor and app:strokeWidth to change the color and the width of the border.
You can also customize the corners using ShapeApperance (it requires version 1.1.0)
<style name="MyButton" parent="Widget.MaterialComponents.Button.OutlinedButton">
<item name="shapeAppearanceOverlay">#style/MyShapeAppearance</item>
</style>
<style name="MyShapeAppearance" parent="">
<item name="cornerFamilyTopLeft">rounded</item>
<item name="cornerFamilyBottomLeft">rounded</item>
<item name="cornerFamilyTopRight">cut</item>
<item name="cornerFamilyBottomRight">cut</item>
<item name="cornerSize">8dp</item>
</style>
The official doc is here and all the android specs here.
With jetpack compose you can use the OutlinedButton and the border attribute:
OutlinedButton(
onClick = { },
border = BorderStroke(1.dp, Color.Blue),
shape = RoundedCornerShape(8.dp)
) {
Text(text = "Save")
}
OLD (support library)
With the new Support Library 28.0.0, the Design Library now contains the Material Button.
You can add this button to our layout file with:
<android.support.design.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="XXXX"
android:textSize="18sp"
app:icon="#drawable/ic_android_white_24dp" />
You can customize the button with these attributes:
app:backgroundTint: Used to apply a tint to the background of the button. If you wish to change the background color of the button, use this attribute instead of background.
app:strokeColor: The color to be used for the button stroke
app:strokeWidth: The width to be used for the button stroke
Also
Here's how to do it correctly.
What you need to do is
1 - Create shape drawable with stroke
2 - Create ripple drawable
3 - Create selector drawable for less than v21
4 - Create a new style for button with border
5 - Apply style on button
1 - Create shape with stroke
btn_outline.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="2dp"
android:color="#color/colorAccent">
</stroke>
<solid android:color="#color/colorTransparent"/>
<corners
android:radius="5dp">
</corners>
</shape>
2 - Create ripple drawable
drawable-v21/bg_btn_outline.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/colorOverlay">
<item>
<shape>
<stroke
android:width="2dp"
android:color="#color/colorAccent"/>
<corners android:radius="5dp"/>
</shape>
</item>
<item android:id="#android:id/mask">
<shape>
<stroke
android:width="2dp"
android:color="#color/colorAccent"/>
<solid android:color="#android:color/white"/>
<corners android:radius="5dp"/>
</shape>
</item>
</ripple>
android:id="#android:id/mask" is required to have ripple touch feedback on the button. The layer that is marked as mask is not visible on screen, its just for touch feedback.
3 - Create selector drawable for less than v21
drawable/bg_btn_outline.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/btn_outline" android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#color/colorOverlay"/>
</shape>
</item>
<item android:drawable="#drawable/btn_outline" android:state_focused="true">
<shape android:shape="rectangle">
<solid android:color="#color/colorOverlay"/>
</shape>
</item>
<item android:drawable="#drawable/btn_outline"/>
</selector>
4 - Create a new style for button with border
All resources that that are needed to create the style are given above, that's how your style should look like
<style name="ButtonBorder" parent="Widget.AppCompat.Button.Colored"/>
<style name="ButtonBorder.Accent">
<item name="android:background">#drawable/bg_btn_outline</item>
<item name="android:textColor">#color/colorAccent</item>
<item name="android:textAllCaps">false</item>
<item name="android:textSize">16sp</item>
<item name="android:singleLine">true</item>
</style>
4 - Apply style on button
<Button
style="#style/ButtonBorder.Accent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
That's pretty much it. Here's a sample of how the buttons looks now.
You could do this pretty easily by setting Material Design Button's style attribute to #style/Widget.MaterialComponents.Button.OutlinedButton and setting app:strokeColor attribute value to your preferred color.
example:
<com.google.android.material.button.MaterialButton
android:text="Rounded outlined button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#+id/btnRound"
style="#style/Widget.MaterialComponents.Button.OutlinedButton"
app:strokeColor="#color/colorPrimaryDark"/>
References:
https://material.io/develop/android/docs/getting-started/
https://material.io/develop/android/components/material-button/
Credits to #NomanRafique for the detailed answer! However, because of the custom background, we've lost a few important things:
Button's height is bigger than the default Widget.AppCompat.Button
Paddings
Enable/Disable states
In case you're wondering, here is how the default background looks like: https://android.googlesource.com/platform/frameworks/support/+/a7487e7/v7/appcompat/res/drawable-v21/abc_btn_colored_material.xml
By reusing original insets, paddings and color selectors, in a simple case we can come up with something like this (all the values are default and come from android support/material library) :
drawable-v21/bg_btn_outlined.xml
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="#dimen/abc_button_inset_horizontal_material"
android:insetTop="#dimen/abc_button_inset_vertical_material"
android:insetRight="#dimen/abc_button_inset_horizontal_material"
android:insetBottom="#dimen/abc_button_inset_vertical_material">
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item>
<shape>
<stroke
android:width="2dp"
android:color="#color/abc_btn_colored_borderless_text_material"/>
<corners android:radius="#dimen/abc_control_corner_material"/>
<padding
android:bottom="#dimen/abc_button_padding_vertical_material"
android:left="#dimen/abc_button_padding_horizontal_material"
android:right="#dimen/abc_button_padding_horizontal_material"
android:top="#dimen/abc_button_padding_vertical_material"/>
</shape>
</item>
<item android:id="#android:id/mask">
<shape>
<stroke
android:width="2dp"
android:color="#color/abc_btn_colored_borderless_text_material"/>
<solid android:color="#android:color/white"/>
<corners android:radius="#dimen/abc_control_corner_material"/>
</shape>
</item>
</ripple>
</inset>
styles.xml
<style name="Button.Outlined" parent="Widget.AppCompat.Button.Borderless.Colored">
<item name="android:background">#drawable/bg_btn_outlined</item>
</style>
At this point, we should have an outlined button that responds to touches, respects the enabled="false" state and of the same height as the default Widget.AppCompat.Button:
Now, from here you can start customizing colors by providing your own implementation of the #color/abc_btn_colored_borderless_text_material color selector.
In your XML use this,
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Its a button"
android:textColor="#android:color/white"
android:textSize="#dimen/_12ssp"
app:backgroundTint="#android:color/transparent"
app:strokeColor="#android:color/white"
app:strokeWidth="#dimen/_1sdp" />
where
app:backgroundTint is used for background color
app:strokeColor is border color
app:strokeWidth is border width
This is how I do buttons only with a border and the ripple effect on Lollipop and above. Just like the AppCompat buttons, these have a fallback pressed effect on lower APIs (if you need ripples on lower APIs, you need to use an external library). I use FrameLayout because it's cheap. The color of the text and the border is black, but you can change it with a custom one:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="#drawable/background_button_ghost">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:selectableItemBackground"
android:gravity="center"
android:padding="14dp"
android:textSize="16sp"
android:textAllCaps="true"
android:textStyle="bold"
android:textColor="#android:color/black"
android:text="Text"/>
</FrameLayout>
drawable/background_button_ghost.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="2dp"
android:color="#android:color/black"/>
<solid android:color="#color/transparent"/>
</shape>
If I have missed something, please leave a comment and I will update the answer.
You can do this with Jetpack Compose too. To do it, just create a composable function with a OutlinedButton and pass the as parameter the border you want:
#Composable
fun OutlineButton() {
OutlinedButton(
onClick = { //TODO - implement click here },
border = BorderStroke(1.dp, Color.Blue), // <-- border property
shape = RoundedCornerShape(corner = CornerSize(20.dp)),
colors = ButtonDefaults.outlinedButtonColors(contentColor = Color.Blue)
){
Text(text = "CONFIRM")
}
}
Just use MaterialButton with an outline style.
<com.google.android.material.button.MaterialButton
...
style="#style/Widget.MaterialComponents.Button.OutlinedButton"
android:text="Delete Mentor Manager"
app:strokeColor="#color/...."
app:strokeWidth="1dp" />
Simply you can use this code. Its looks soo Good.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:orientation="vertical">
<android.support.v7.widget.AppCompatButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#F48025"
android:text="login"
android:textColor="#color/colorWhite" />
</LinearLayout>
Here border color is:
android:background="#ffffff"
And background color is:
android:backgroundTint="#F48025"
<Button
android:id="#+id/btn_add_discussion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="15dp"
android:padding="8dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="5dp"
android:backgroundTint="#80ffffff"
android:textColor="#color/colorPrimaryDark"
style="#style/btn_start_new_discussion"
android:text="Start new discussion" />
Put below code in Styles.xml file :
<style name="btn_start_new_discussion">
<item name="android:layout_marginTop">15dp</item>
<item name="strokeWidth">2dp</item>
<item name="strokeColor">#color/colorPrimary</item>
<item name="cornerRadius">10dp</item>
</style>
I have a Button in my layout whose background and textcolor are defined as selectors. When unpressed the button has a background color and a textcolor and when pressed another color and another text color - e.g. white background with black text -> black background with white text.
At a certain point in my code I need to replace the background/text color with a third set of colors and then go back to the original selector defined in the xml. However, after going back the text no longer appears and instead I get just a solid colored button.
<Button
android:id="#+id/somebutton"
android:layout_width="80"
android:layout_height="80"
android:textColor="#color/sometext_selector"
android:background="#drawable/somebackground_selector"
android:gravity="center"
android:text="#string/sometext"
android:textSize="15sp"
/>
At this point everything is fine, but when I do this:
someButton.setBackgroundDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.backgroundRed, null));
someButton.setTextColor(getResources().getColor(android.R.color.holo_red_light));
and then afterwards this:
someButton.setBackgroundDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.originalBackgroundSelectorDefinedInXml, null));
someButton.setTextColor(getResources().getColor(R.color.originalTextSelectorDefinedInXml));
is when the problems begin.
Here are the xmls for my selectors - apologies for pseudocode, just imagine appropriate hex values:
First - the background:
<item android:drawable="#drawable/color_purple_full" android:state_selected="true"/>
<item android:drawable="#drawable/color_purple_full" android:state_pressed="true"/>
<item android:drawable="#drawable/color_purple_full" android:state_focused="true"/>
<item android:drawable="#drawable/color_purple_outline"/>
color_purple_outline:
android:shape="oval">
<stroke android:width="2dp" android:color="#somepurplehexa" />
<size android:width="80dp" android:height="80dp"/> </shape>
color_purple_full:
android:shape="oval">
<solid android:color="#somepurplehexa"/>
<size android:width="80dp" android:height="80dp" /> </shape>
for text:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#android:color/black" android:state_selected="true"/>
<item android:color="#android:color/black" android:state_pressed="true"/>
<item android:color="#android:color/black" android:state_focused="true"/>
<item android:color="#color/green"/>
What I'm seeing is the correct background in the unpressed state but in the pressed state I'm just getting a solid color with no text on it at all. I'd be grateful for any ideas as to why this is happening and why in the original xml it works fine but only stops working after changing it programmatically?
SOLVED:
turns out the problem was here:
someButton.setTextColor(getResources().getColor(R.color.originalTextSelectorDefinedInXml));
should have been
someButton.setTextColor(getResources().getColorStateList(R.color.originalTextSelectorDefinedInXml));
I would like to remove the padding around text in Button view.
The first screenshot is the result I would achieve, and the second one is the state of the art.
Of course, I have defined a custom drawable to get the button appearance. But even if I set the padding attribute to 0dp the result does not change.
Any suggestion, please?
EDIT
Here is the xml code of the button
<Button
android:id="#+id/btnCancel"
style="#style/dark_header_button"
android:layout_width="wrap_content"
android:layout_marginLeft="10dp"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:padding="0dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:text="#android:string/cancel" />
Here is the style xml file:
<style name="dark_header_button">
<item name="android:background">#drawable/bkg_dark_header_button</item>
<item name="android:shadowDy">-1</item>
<item name="android:shadowColor">#000000</item>
<item name="android:shadowRadius">1</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">#ffffff</item>
</style>
and here is the drawable xml file:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape>
<corners android:radius="10dp" />
<gradient
android:angle="90"
android:endColor="#060606"
android:startColor="#707070"
android:type="linear" />
</shape>
</item>
<item>
<shape>
<corners android:radius="10dp" />
<gradient
android:angle="90"
android:endColor="#707070"
android:startColor="#060606"
android:type="linear" />
<stroke
android:width="0.5dp"
android:color="#2b2b2b" />
</shape>
</item>
</selector>
Its not actually padding but the theme is setting a minHeight and minWidth for button widgets. You can completely remove this effect without changing your theme by setting the following on your button in the xml:
android:minHeight="0dp"
android:minWidth="0dp"
It thus also implies that you can play around with different settings for different effects, 0dp is merely an example to completely remove this effect.
you can try using android:includeFontPadding. set it to false. also set the padding to 0.
Button text doesn't need padding, it is by default in center of the button.
I think you are using the android:theme="#android:style/Theme.Black.NoTitleBar" in the manifest file, please remove it and use native app Theme and try it.
I am looking to style the tab indicator like pininterest where the indicator does not look like the normal "android" style . Is there some attribute where i can set the indicator height ?Please look into the following image .
It might be not a proper solution, and question is really old, but as I haven't found any proper solutions, this is how I did it:
I created a layerList file called indicator:
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#FF0000" />
</shape>
</item>
<item android:bottom="3dp">
<shape android:shape="rectangle">
<solid android:color="#efefef" />
</shape>
</item>
</layer-list>
And just set it as my tab indicator background:
<style name="CustomTabPageIndicator" parent="#android:style/Widget.Holo.ActionBar.TabView">
<item name="android:background">#drawable/indicator</item>
</style>
I've also applied this theme to my actionBar:
<style name="MyActionBarTheme" parent="android:style/Widget.Holo.ActionBar">
<item name="android:actionBarTabStyle">#style/CustomTabPageIndicator</item>
</item> </style>
It works because in indicator.xml first shape is lower shape, which is actual indicator, and to I set its height by providing bottom padding for another shape which color is identical to actionbar color.
just set layout_height attribute in your layout file:
com.viewpagerindicator.TitlePageIndicator
android:layout_height="#dimen/indicator_height"
Using the material design TabLayout, You can set the height with app:tabIndicatorHeight
<com.google.android.material.tabs.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorHeight="4dp" />