Change shape of Button while mantaining its material design ripple effect - android

I want to create Button with custom shape , which would react on press like in theme "Base.Widget.AppCompat.Button.Colored".
However bacause of I have to customize its shape (rounded corners I have to override its android:background - this is so far the only way I know (no... no I will not use dirty hacks with FrameLayout).
Currently it can be done only by providing our custom <shape> in xml file as background drawable.
The most promising code, which enable selectableItemBackground - so imporant for me, is:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="#color/colorAccent"/>
<corners android:topLeftRadius="#dimen/button_shape_radius"
android:topRightRadius="#dimen/button_shape_radius"/>
</shape>
</item>
<item android:drawable="?attr/selectableItemBackground">
<shape>
<solid/>
<corners android:topLeftRadius="#dimen/button_shape_radius"
android:topRightRadius="#dimen/button_shape_radius"/>
</shape>
</item>
</layer-list>
Unfortunatelly I cannot shape second item with <item android:drawable="?attr/selectableItemBackground"> therefore in the end pressed item's shape is rectangle.
I would appreaciate if someone will give me soulution for this problem.
I use API_MIN = 16, so cannot use ripple effect. I also dont want to use FrameLayout or tther external Library that forces me to wrapp Button with something.

To have a ripple below 21 you can use this library Ripple Effect you use your shape without the ripple tag and surround the view with RippleView for more details you can check the Usage section
21+ you can try this i didn't test it but it should work, put this in the folder drawable-v21
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item>
<shape>
<solid android:color="#color/colorAccent"/>
<corners android:topLeftRadius="#dimen/button_shape_radius"
android:topRightRadius="#dimen/button_shape_radius"/>
</shape>
</item>
<item android:drawable="?attr/selectableItemBackground">
<shape>
<solid/>
<corners android:topLeftRadius="#dimen/button_shape_radius"
android:topRightRadius="#dimen/button_shape_radius"/>
</shape>
</item>
</ripple>
UPDATE
I changed the source code of Ripple Effect to a button
You can get the code here
USAGE
Just like any ordinary button XML
<path.to.the.RippleButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/button_rounded_top_blue"
android:id="#+id/mybutton"/>
Java
RippleButton button = (RippleButton) findViewById(R.id.mybutton);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(MainScreen.this, "You did it", Toast.LENGTH_SHORT).show();
}
});
If you need other view you just need to make some tweaks to the source code it's easy (in my opinion)

Related

Issue regarding ripple effect in Android

I want to implement a ripple effect while I press my button . The border of the button has been made by me (mentioned in the item tag at the end) . Also I want a bordered ripple hence I use "mask" as the id. If I don't implement solid tags and a color to it inside the mask , ripple effect is not implemented . What could be the reason for it
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/colorHighlighted">
<item android:id="#android:id/mask">
<shape android:shape="oval">
<solid android:color="#color/teal_700"/>
</shape>
</item>
<item android:drawable="#drawable/item_circular_color_accent_border"/>
</ripple>

Change color of button programmatically

First of, I have read the multiple topics about this subject here on SO. Methods like PorterDuff colorfilter and changing setBackgroundResource. They all work but with strange hiccups that happen at complete random.
I have a button with following style (unpressed state = white, pressed = gray):
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<layer-list>
<item>
<shape>
<solid android:color="#ffafafaf" />
<corners android:radius="30dip"/>
</shape>
</item>
</layer-list>
</item>
<item>
<layer-list>
<!-- SHADOW LAYER -->
<item>
<shape>
<solid android:color="#66000000" />
<corners android:radius="30dp"/>
</shape>
</item>
<!-- CONTENT LAYER -->
<item android:left="1dp" android:top="1dp" android:bottom="2dp" android:right="2dp">
<shape>
<solid android:color="#ffffff" />
<corners android:radius="30dp"/>
</shape>
</item>
</layer-list>
</item>
</selector
>
So to make this button green instead of white when clicked I have tried two different approaches. First one
button.getBackground().setColorFilter(Color.GREEN, PorterDuff.Mode.SRC_ATOP);
Than to make it go back to normal (white) I do:
Drawable d = button.getBackground();
button.invalidateDrawable(d);
d.clearColorFilter();
This make the button go back to normal (white), but when I press it isn't gray (as it was before setColorFilter) but green. Somehow the colorfilter got transferred to the buttons pressed state.
Second approach. I created an additional drawable button style identical to my normal one except for item color being green (instead of white)
So with this approach I can change the button color like this:
b6.setBackgroundResource(R.drawable.green_button);
And I change it back to normal:
b6.setBackgroundResource(R.drawable.normal_button);
This works as expected except for a strange behavior that happens 1/10 when I try to reset the button back to normal. The button becomes gray and it seems like it didn't read the setBackgroundResource. This happens all random and nothing in the logcat revile anything.
Please somebody help me figure out what is causing this or proposing your method for doing this. I would rather not use an imagebutton with a textfield overlapping the button with relative layout, than change color by changing imagebutton rsc. But please there has to be another way?
Invalidate your button to force a refresh.
b6.invalidate();
That way your button should be redrawn every time.

Material Design suggestions for edit button for each item

I wanted to add an edit button to each button in a list of items. Android action buttons should only be used once per view so those don't make sense. Is there any other way of doing it by following material guidelines? This button should be something that flies off and flies on depending on whether the overall edit button is pressed or not.
You should use flat buttons because buttons pop from backgrounds, easily grab attention, and guide the user’s eye. Here is a nice post about this
UPDATED:
To design a flat button effect you have to do the following
define your button and set background to a drawable which contains definitions for status pressed and status default
for status pressed write a drawable resource with solid color
for status default write a drawable with a item pointing to status pressed drawable as a background. And draw a lighter shape as another item with a android:bottom="2dp"
flat_button.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="#drawable/rect_pressed"/>
<item android:drawable="#drawable/rect_normal"/>
</selector>
rect_normal.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/rect_pressed" />
<item android:bottom="#dimen/layer_padding">
<shape android:shape="rectangle">
<corners android:radius="#dimen/corner_radius" />
<solid android:color="#color/blue_normal" />
</shape>
</item>
</layer-list>
rect_pressed.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="#dimen/corner_radius" />
<solid android:color="#color/blue_pressed" />
</shape>
if you need to read the full tutorial go here.
You should probably use flat or raised button (depending on how important your edit function is).

Android unbounded ripple and background

it is possible to create a RippleDrawable defining an unbounded ripple and at the same time a background color?
I've tried everything but when i define a shape and its color the ripple is not unbounded anymore.
Also in this page https://developer.android.com/reference/android/graphics/drawable/RippleDrawable.html there is no reference about adding an unbounded ripple over a shape.
I've tried with this layer-list but the result is awful
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<ripple
android:color="#color/android_l_light_gray">
</ripple>
</item>
<item>
<shape
android:shape="rectangle">
<solid android:color="#color/android_l_dark_gray" />
</shape>
</item> </layer-list>
this is what i get
First off keep in mind that layer-list drawable works similar to FrameLayout, it stacks items as they appear so if you want to have your ripple in front just move it down
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:shape="rectangle">
<solid android:color="#color/android_l_dark_gray"/>
</shape>
</item>
<item>
<ripple android:color="#color/android_l_light_gray"/>
</item>
</layer-list>
Produces something like
Now you notice how it gets "clipped" by the other buttons? it is actually being overdrawn, this is because of draw order, the other views' background get drawn on top, not that the ripple is actually getting clipped, so I can think of a few solutions for your particular layout:
a. Get rid of the layer-list drawable and use just ripple as your button background, use your shape or color drawable as your ViewGroup background, producing:
Notice that you lost your grid like effect due your other background, but take a look at other number pads on lollipop and you will notice they don't have grid dividers, if you still want them use your ViewGroup to draw them.
b. Use/draw your ripple as foreground/overlay/drawableTop drawable, and the other one as background, but I think you might run into a similar issue with drawing order as before.
c. Had another one in mind but I just forgot, might come back as a dream ¯\_(ツ)_/¯
Check out Calculator from AOSP, you might want to borrow CalculatorPadLayout for your grid, or just learn how they do it :)
XML
<Button
android:id="#+id/btn_key_seven"
style="#style/AppTheme.KeypadButton"
android:text="#string/str_one" />
STYLE
<style name="AppTheme.KeypadButton" parent="Base.Widget.AppCompat.Button.Borderless">
<item name="android:background">#drawable/button_ripple_effect_unbounded</item>
<item name="android:colorBackground">#color/colorPrimaryDark</item>
</style>
Drawable
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<ripple android:color="#color/colorPrimaryDark"/>
</item>
</layer-list>```
Working awesome for me

How to Set Opacity (Alpha) for View in Android

I have a button as in the following:
<Button
android:text="Submit"
android:id="#+id/Button01"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</Button>
In my onCreate() event, I am calling Button01 like this:
setContentView(R.layout.main);
View Button01 = this.findViewById(R.id.Button01);
Button01.setOnClickListener(this);
There is a background in the application, and I want to set an opacity on this submit button. How can I set an opacity for this view? Is it something that I can set on the java side, or can I set in the main.xml file?
On the java side I tried Button01.mutate().SetAlpha(100), but it gave me an error.
I'm amazed by everyone else's MUCH more complicated answers.
XML
You can very simply define the alpha in the color definition of the button (or any other view) in your xml:
android:color="#66FF0000" // Partially transparent red
In the above example, the color would be a partially transparent red.
When defining the color of a view, the format can be either #RRGGBB or #AARRGGBB, where AA is the hex alpha value. FF would be fully opaque and 00 would be full transparent.
Dynamically
If you need to dynamically alter the opacity in your code, use
myButton.getBackground().setAlpha(128); // 50% transparent
Where the INT ranges from 0 (fully transparent) to 255 (fully opaque).
I guess you may have already found the answer, but if not (and for other developers), you can do it like this:
btnMybutton.getBackground().setAlpha(45);
Here I have set the opacity to 45. You can basically set it from anything between 0(fully transparent) to 255 (completely opaque)
Much more easier from the above.
Default alpha attribute is there for button
android:alpha="0.5"
The range is between 0 for complete transparent and 1 for complete opacity.
What I would suggest you do is create a custom ARGB color in your colors.xml file such as :
<resources>
<color name="translucent_black">#80000000</color>
</resources>
then set your button background to that color :
android:background="#android:color/translucent_black"
Another thing you can do if you want to play around with the shape of the button is to create a Shape drawable resource where you set up the properties what the button should look like :
file: res/drawable/rounded_corner_box.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#80000000"
android:endColor="#80FFFFFF"
android:angle="45"/>
<padding android:left="7dp"
android:top="7dp"
android:right="7dp"
android:bottom="7dp" />
<corners android:radius="8dp" />
</shape>
Then use that as the button background :
android:background="#drawable/rounded_corner_box"
I just found your question while having the similar problem with a TextView. I was able to solve it, by extending TextView and overriding onSetAlpha. Maybe you could try something similar with your button:
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
public class AlphaTextView extends TextView {
public AlphaTextView(Context context) {
super(context);
}
public AlphaTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AlphaTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onSetAlpha(int alpha) {
setTextColor(getTextColors().withAlpha(alpha));
setHintTextColor(getHintTextColors().withAlpha(alpha));
setLinkTextColor(getLinkTextColors().withAlpha(alpha));
return true;
}
}
According to the android docs view alpha is a value between 0 and 1. So to set it use something like this:
View v;
v.setAlpha(.5f);
android:background="#android:color/transparent"
The above is something that I know...
I think creating a custom button class is the best idea
API Level 11
Recently I came across this android:alpha xml attribute which takes a value between 0 and 1. The corresponding method is setAlpha(float).
Although btnMybutton.getBackground().setAlpha(45); is nice idea, it just apply alpha to background and not the whole view.
If you want apply alpha to view use btnMybutton.setAlpha(0.30f); instead. This apply opacity to View. It accepts a value between 0 and 1.
Doc says:
Sets the opacity of the view. This is a value from 0 to 1, where 0
means the view is completely transparent and 1 means the view is
completely opaque. If this view overrides onSetAlpha(int) to return
true, then this view is responsible for applying the opacity itself.
Otherwise, calling this method is equivalent to calling
setLayerType(int, android.graphics.Paint) and setting a hardware
layer. Note that setting alpha to a translucent value (0 < alpha < 1)
may have performance implications. It is generally best to use the
alpha property sparingly and transiently, as in the case of fading
animations.
For a view you can set opacity by the following.
view_name.setAlpha(float_value);
The property view.setAlpha(int) is deprecated for the API version greater than 11. Henceforth, property like .setAlpha(0.5f) is used.
I've run into this problem with ICS/JB because the default buttons for the Holo theme consist of images that are slightly transparent. For a background this is especially noticeable.
Gingerbread vs. ICS+:
Copying over all of the drawable states and images for each resolution and making the transparent images solid is a pain, so I've opted for a dirtier solution: wrap the button in a holder that has a white background. Here's a crude XML drawable (ButtonHolder) which does exactly that:
Your XML file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="#style/Content">
<RelativeLayout style="#style/ButtonHolder">
<Button android:id="#+id/myButton"
style="#style/Button"
android:text="#string/proceed"/>
</RelativeLayout>
</LinearLayout>
ButtonHolder.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#color/white"/>
</shape>
</item>
</layer-list>
styles.xml
.
.
.
<style name="ButtonHolder">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:background">#drawable/buttonholder</item>
</style>
<style name="Button" parent="#android:style/Widget.Button">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:textStyle">bold</item>
</style>
.
.
.
However, this results in a white border because the Holo button images include margins to account for the pressed space:
So the solution is to give the white background a margin (4dp worked for me) and rounded corners (2dp) to completely hide the white yet make the button solid:
ButtonHolder.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#android:color/transparent"/>
</shape>
</item>
<item android:top="4dp" android:bottom="4dp" android:left="4dp" android:right="4dp">
<shape android:shape="rectangle">
<solid android:color="#color/white"/>
<corners android:radius="2dp" />
</shape>
</item>
</layer-list>
The final result looks like this:
You should target this style for v14+, and tweak or exclude it for Gingerbread/Honeycomb because their native button image sizes are different from ICS and JB's (e.g. this exact style behind a Gingerbread button results in a small bit of white below the button).
For API < 11 for textView color I did the following:
int textViewColor = textView.getTextColors().getDefaultColor();
textView.setTextColor(Color.argb(128, Color.red(textViewColor), Color.green(textViewColor), Color.blue(textViewColor))); //50% transparent
A little cumbersome, but hey, it works :-)
If you use Kotlin , it's very easy to set alpha like this
imageView.alpha= 0.5F
where the value must be a float number.
I know this already has a bunch of answers but I found that for buttons it is just easiest to create your own .xml selectors and set that to the background of said button. That way you can also change it state when pressed or enabled and so on. Here is a quick snippet of one that I use. If you want to add a transparency to any of the colors, add a leading hex value (#XXcccccc). (XX == "alpha of color")
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" >
<shape>
<solid
android:color="#70c656" />
<stroke
android:width="1dp"
android:color="#53933f" />
<corners
android:radius="4dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
<item>
<shape>
<gradient
android:startColor="#70c656"
android:endColor="#53933f"
android:angle="270" />
<stroke
android:width="1dp"
android:color="#53933f" />
<corners
android:radius="4dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
</selector>

Categories

Resources