I want to set the android:id = "#android:id/background" programmatically.
I try to adapting drawable xml code to java code programmatically.
I wrote other options to code, but couldn't write the android:id = "#android:id/background" to code.
here is my code. please let me know the way.
xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<shape android:shape="rectangle">
<corners android:radius="10dp"/>
<solid android:color="#color/colorOrange"/>
<stroke android:color="#fff" android:width="1dp"/>
</shape>
</item>
<item android:id="#android:id/progress">
<scale
android:scaleHeight="10%"
android:scaleWidth="100%" >
<shape android:shape="rectangle">
<corners android:radius="10dp"/>
<solid android:color="#color/colorGreen"/>
<stroke android:color="#color/colorGreen"
android:width="4dp"/>
</shape>
</scale>
</item>
</layer-list>
code
val layer1 = GradientDrawable()
layer1.cornerRadius = 10f
layer1.setStroke(1, Color.WHITE)
layer1.setColor(Color.YELLOW)
val scaleDrawable = GradientDrawable()
scaleDrawable.cornerRadius = 10f
scaleDrawable.setStroke(1, Color.WHITE)
scaleDrawable.setColor(Color.BLUE)
val layer2 = ScaleDrawable(scaleDrawable, Gravity.BOTTOM,1f,0.1f)
val drawableList = arrayOf(layer1, layer2)
val layerList : LayerDrawable = LayerDrawable(drawableList)
this.progressDrawable = layerList
result screen
You can use #layerList.setId and set the id by index . Check the code below . I have made few changes in it to match it to xml-drawable .
val layer1 = GradientDrawable()
layer1.cornerRadius = 10f
layer1.setStroke(1, Color.WHITE)
layer1.setColor(Color.YELLOW)
val scaleDrawable = GradientDrawable()
scaleDrawable.cornerRadius = 10f
scaleDrawable.setStroke(1, Color.WHITE)
scaleDrawable.setColor(Color.BLUE)
val layer2 = ScaleDrawable(scaleDrawable, Gravity.START,1f,0.1f)
val drawableList = arrayOf(layer1, layer2)
val layerList = LayerDrawable(drawableList)
layerList.setId(0,android.R.id.background)
layerList.setId(1,android.R.id.progress)
seekBar.progressDrawable = layerList
Related
I would like to change an existing drawable state list (default and pressed) colours programmatically.
This is my custom drawable I would like to edit:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<ripple android:color="#1AFFFFFF">
<item>
<shape android:shape="rectangle">
<solid android:color="#color/colorPrimary" />
<corners android:radius="5dp" />
</shape>
</item>
</ripple>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="#color/colorPrimary" />
<corners android:radius="5dp" />
</shape>
</item>
</selector>
I've tried How can I change colors in my StateListDrawable? but I am getting an error:
val customButtonTest: Drawable
get() {
val stateListDrawable = ContextCompat.getDrawable(context, R.drawable.custom_button) as StateListDrawable
val drawableContainerState = stateListDrawable.constantState as DrawableContainer.DrawableContainerState
val children = drawableContainerState.children
val selectedItem = children[0] as GradientDrawable
selectedItem.setColor(Color.parseColor("#FD00DF"))
return stateListDrawable.current
}
**ClassCastException: android.graphics.drawable.RippleDrawable cannot be cast to android.graphics.drawable.GradientDrawable**
As I am intend to use it for a BandingAdapter, how can I change both state colours and return it as a drawable?
Thanks
** Edited ---
val customButtonTest: Drawable
get() {
val stateListDrawable =
ContextCompat.getDrawable(context, R.drawable.custom_button) as StateListDrawable
val drawableContainerState =
stateListDrawable.constantState as DrawableContainer.DrawableContainerState
val children = drawableContainerState.children
val pressedState = children[0] as RippleDrawable
val defaultState = children[1] as GradientDrawable
pressedState.setColor(ColorStateList.valueOf(Color.parseColor("#1AFFFFFF")))
defaultState.setColor(Color.parseColor("#4267b2"))
drawableContainerState.addChild(pressedState)
drawableContainerState.addChild(defaultState)
return drawableContainerState.newDrawable()
}
How to change an item solid colour inside the ripple container? As
pressedState.setColor(ColorStateList.valueOf(Color.parseColor("#1AFFFFFF")
changes ripple colour itself.
If someone needs to access ripple and its child, here you go:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<ripple android:color="#1A1C1C1C">
<item>
<shape android:shape="rectangle">
<solid android:color="#color/colorPrimary" />
<corners android:radius="5dp" />
</shape>
</item>
</ripple>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="#color/colorPrimary" />
<corners android:radius="5dp" />
</shape>
</item>
</selector>
val customButtonTest: Drawable
get() {
val stateListDrawable = ContextCompat.getDrawable(context, R.drawable.custom_button) as StateListDrawable
val drawableContainerState = stateListDrawable.constantState as DrawableContainer.DrawableContainerState
val children = drawableContainerState.children
val pressedState = children[0] as RippleDrawable
val defaultState = children[1] as GradientDrawable
val layerDrawable = pressedState as LayerDrawable
val rippleChildDrawable = layerDrawable.getDrawable(0) as GradientDrawable
rippleChildDrawable.setColor(primaryColor)
defaultState.setColor(primaryColor)
return drawableContainerState.newDrawable()
}
To reach <items> inside <ripple> you need to cast RippleDrawable to LayerDrawable
So I've implemented a custom button for our app, the implementation works perfect on Android 6 and up but I run into an issue on Android 5, where the background color doesn't get applied until I press the button once. Then it looks as it should.
Buttons not correct
Buttons correct
The implementation looks like this:
class MpButton #JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.style.ButtonStyle) : AppCompatButton(context, attrs, defStyleAttr) {
private val toScale = 0.9f
private val fromScale = 1f
init {
var style = 0
var allCaps = false
attrs?.let {
val a = context.obtainStyledAttributes(it, R.styleable.MpButton)
style = a.getInt(R.styleable.MpButton_MpButtonColor, 0)
allCaps = a.getBoolean(R.styleable.MpButton_MpButtonAllcaps, false)
a.recycle()
}
when (style) {
WHITE -> {
this.setBackgroundResource(R.drawable.mp_button_white)
this.setTextColor(ContextCompat.getColor(context, R.color.white))
}
RED -> {
this.setBackgroundResource(R.drawable.mp_button_red)
this.setTextColor(ContextCompat.getColor(context, R.color.white))
}
BLACK -> {
this.setBackgroundResource(R.drawable.mp_button_black)
this.setTextColor(ContextCompat.getColor(context, R.color.mp_black))
}
BLUE -> {
this.setBackgroundResource(R.drawable.mp_button_blue)
this.setTextColor(ContextCompat.getColor(context, R.color.white))
}
YELLOW -> {
this.setBackgroundResource(R.drawable.mp_button_yellow)
this.setTextColor(ContextCompat.getColor(context, R.color.white))
}
else -> {
this.setBackgroundResource(R.drawable.mp_button_green)
this.setTextColor(ContextCompat.getColor(context, R.color.white))
}
}
this.gravity = Gravity.CENTER
val padding = Utils.convertDpToPixel(context, 5)
this.setPadding(padding, padding, padding, padding)
this.isAllCaps = allCaps
}
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
when(event.action) {
MotionEvent.ACTION_DOWN -> {
this.animate().scaleX(toScale).scaleY(toScale).setDuration(100).start()
}
MotionEvent.ACTION_UP -> {
this.animate().scaleX(fromScale).scaleY(fromScale).setDuration(100).start()
}
}
return super.dispatchTouchEvent(event)
}
companion object {
const val WHITE = 1
const val RED = 2
const val BLACK = 3
const val BLUE = 4
const val YELLOW = 5
}
}
For info Ill also add the XML for one of the colors:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/mp_black">
<item>
<selector
android:exitFadeDuration="#android:integer/config_mediumAnimTime"
android:enterFadeDuration="#android:integer/config_shortAnimTime">
<item android:state_enabled="true" android:state_pressed="false">
<shape android:shape="rectangle">
<corners android:radius="30dp"/>
<solid android:color="#color/jungle_green" />
</shape>
</item>
<item android:state_enabled="true" android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="30dp"/>
<solid android:color="#color/forest" />
</shape>
</item>
<item android:state_enabled="false">
<shape android:shape="rectangle">
<corners android:radius="30dp"/>
<solid android:color="#color/mp_gray_5" />
</shape>
</item>
</selector>
</item>
</ripple>
As a last ill copy the part of the XML of the view aswell to give as much info as possible:
<se.motesplatsen.app.ui.controls.MpButton
android:id="#+id/btnStartLogin"
android:layout_width="220dp"
android:layout_height="44dp"
android:text="#string/DEFAULT_LOGIN"
android:layout_marginBottom="10dp"
android:layout_marginTop="20dp"
app:MpButtonAllcaps="true"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/btnStartBecomeMember"/>
<se.motesplatsen.app.ui.controls.MpButton
android:id="#+id/btnStartBecomeMember"
android:layout_width="220dp"
android:layout_height="44dp"
android:layout_marginTop="25dp"
android:text="#string/BECOME_MEMBER_BUTTON"
app:MpButtonColor="1"
app:MpButtonAllcaps="true"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintTop_toBottomOf="#id/tvStartDesc"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toTopOf="#id/btnStartLogin"/>
UPDATE & SOLUTION!:
Finally got this to work! Solution was to remove
android:exitFadeDuration="#android:integer/config_mediumAnimTime"
android:enterFadeDuration="#android:integer/config_shortAnimTime"
Im guessing it somehow interferes with the ripple animation on certain Android versions. So for anyone else that have my issue, check so you dont have Ripple togheter with fadeduration in the selector :)!
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape >
<solid android:color="#android:color/white"/>
<size android:height="1dp"/>
</shape>
</item>
<item android:bottom="2dip" android:top="2dip" android:left="2dip" android:right="2dip">
<shape>
<solid android:color="#android:color/Transparent"/>
</shape>
</item>
this is exactly look like your correct button
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<corners
android:radius="5dp"
/>
<solid
android:color="#color/Transparent"
/>
just use this as background you are using on pressed state in your file
I have a SeekBar in my anko dsl (i use 0.10.4) layout like this
seekBar {
max = 2
progress = 1
progressDrawable = drawable(R.drawable.seek_bar_progress)
thumb = drawable(R.drawable.seek_bar_thumb)
onSeekBarChangeListener {
onProgressChanged { _, progress, _ ->
// Something
}
}
}.lparams(matchParent) {
setMargins(dip(16), dip(8), dip(16), dip(8))
}
seek_bar_progress.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#D9D9D9"/>
</shape>
</item>
<item android:id="#android:id/progress">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#color/colorRed"/>
</shape>
</item>
seek_bar_thumb.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item >
<shape android:shape="oval">
<solid android:color="#color/colorRed"/>
<size android:height="26dp" android:width="26dp"/>
</shape>
</item>
and i have ugly view with this settings on any android devices
see picture.
But when i use "include" tag i have a correct seekbar implementation see picture
include<SeekBar>(R.layout.seek_lay) {
progress = 1
onSeekBarChangeListener {
onProgressChanged { _, progress, _ ->
// Something
}
}
}.lparams(matchParent) {
setMargins(dip(16), dip(8), dip(16), dip(8))
}
seek_lay.xml
<SeekBar xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:max="2"
android:maxHeight="2dp"
android:minHeight="2dp"
android:progress="1"
android:progressDrawable="#drawable/seek_bar_progress"
android:thumb="#drawable/seek_bar_thumb"
/>
does anybody faces with the same problem? And how i can resolve this if it's possible?
Thanks
I face the same problem today.. And I search for hours to solve this problem too, but I could not find any 'normally' solution at all.
Finally I change the field mMaxHeight with java reflection to achieve the result.
Just notice that mMaxHeight belong to ProgressBar.class, so you need to use ProgressBar.class to find it.
val field = ProgressBar::class.java.getDeclaredField("mMaxHeight")
val accessible = field.isAccessible
field.isAccessible = true
field.setInt(seekBar, [value])
field.isAccessible = accessible
Result
I dont know it is a good or bad way, it just can work for me.
In my app, I have the selector below.
Is possible to create a similar selector, by color instead of by image-drawable, but at runtime?
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_window_focused="false"
android:drawable="#drawable/ic_button_orange_normal" />
<item
android:state_pressed="true"
android:drawable="#drawable/ic_button_orange_pressed" />
<item
android:state_focused="true"
android:drawable="#drawable/ic_button_orange_focused" />
<item
android:drawable="#drawable/ic_button_orange_normal" />
</selector>
I have tried the function below to create the selector in runtime, but I need to create a round button, not square.
Is this possible?
private StateListDrawable makeSelector(int color)
{
StateListDrawable res = new StateListDrawable();
res.setExitFadeDuration(400);
res.setAlpha(45);
ShapeDrawable d = new ShapeDrawable();
res.addState(new int[] { android.R.attr.state_pressed }, new ColorDrawable(ColorUtilities.decrease(color, 0x003030)));
res.addState(new int[] {}, new ColorDrawable(Color.TRANSPARENT));
return res;
}
Edit again... I have found the way to create round selectors...
private static ShapeDrawable getRoundShapeDrawable(int color)
{
ShapeDrawable shape_drawable = new ShapeDrawable(new OvalShape());
shape_drawable.getPaint().setColor(color);
return shape_drawable;
}
public static StateListDrawable getRoundShapeSelector(int normal_color, int pressed_color)
{
ShapeDrawable normal_shape_drawable = getRoundShapeDrawable(normal_color), pressed_shape_drawable = getRoundShapeDrawable(pressed_color);
StateListDrawable state_list_drawable = new StateListDrawable();
state_list_drawable.addState(new int[] { android.R.attr.state_pressed }, pressed_shape_drawable);
state_list_drawable.addState(new int[] { android.R.attr.state_focused }, pressed_shape_drawable);
state_list_drawable.addState(new int[] { }, normal_shape_drawable);
return state_list_drawable;
}
You can use "StateListDrawable"
StateListDrawable
and add state in it.
Let me know if you face problem in implementing this.
If you want to create a round button. Then you can use layer-list then add this drawable xml as a Layer.
Eg. How to create round button.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:bottom="0dp"
android:left="0dp"
android:right="0dp"
android:top="0dp">
<shape android:shape="rectangle" >
<corners android:radius="40dp" />
<solid android:color="#fff" />
</shape>
</item>
<item
android:bottom="1dp"
android:left="1dp"
android:right="1dp"
android:top="1dp">
<shape android:shape="rectangle" >
<corners android:radius="40dp" />
<solid android:color="#d3d3d3" />
</shape>
</item>
<item
android:bottom="1dp"
android:left="2dp"
android:right="1dp"
android:top="2dp">
<shape android:shape="rectangle" >
<corners android:radius="40dp" />
<solid android:color="#EBEBEB" />
</shape>
</item>
<item
android:id="#+id/wl_btn_bg_shape"
android:bottom="6dp"
android:left="6dp"
android:right="6dp"
android:top="6dp">
<shape android:shape="rectangle" >
<corners android:radius="40dp" />
<solid android:color="#00caa8" />
</shape>
</item>
</layer-list>
create and save about code in drawable as wl_btn_bg.xml
Now you need to add this xml as view background
LayerDrawable layers = (LayerDrawable) context.getResources().getDrawable(R.drawable.wl_btn_bg);
view.setBackground(layers);
and if you want to change the color of selector then you need to add following lines in layers
LayerDrawable layers = (LayerDrawable) context.getResources().getDrawable(R.drawable.wl_btn_bg);
GradientDrawable shape = (GradientDrawable) (layers.findDrawableByLayerId(R.id.wl_btn_bg_shape));
shape.setColor(Color.parseColor("#ff6655"));
Done....
I am developing small android application in which I set drawable resource as background for linear layout. Now what I want to do change background color of linear layout dynamically, but within drawable resource.
My code looks like :
// bcd.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:endColor="#22000000"
android:startColor="#22000000"
android:angle="270" />
<stroke
android:width="3dp"
android:color="#color/white" />
<corners
android:radius="3dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
<LinearLayout
android:id="#+id/lin_llt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
and I set background for linear layout in my activity like this...
parentLayout = (LinearLayout) view.findViewById(R.id.lin_llt);
parentLayout.setBackgroundResource(R.drawable.bcd);
Now what I want to do i want to change color of my drawable resource that mean change color of my linear layout with rounded corner and padding define in drawable..
I tried this in following way
ShapeDrawable bgShape = (ShapeDrawable )parentLayout.getBackground();
bgShape.getPaint().setColor(Color.BLACK);
but its not working for me. any other solution .
So how to do it...
Need help...
thank you...
Change the layout color dynamically
LinearLayout Layout = (LinearLayout) findViewById(R.layout.id);
Layout.setBackgroundColor(Color.parseColor("#ffffff"));
Dynamically set the background color gradient
View layout = findViewById(R.id.mainlayout);
GradientDrawable gd = new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
new int[] {0xFF616261,0xFF131313});
gd.setCornerRadius(0f);
layout.setBackgroundDrawable(gd);
You could try something like this :
Drawable sampleDrawable = context.getResources().getDrawable(R.drawable.balloons);
sampleDrawable.setColorFilter(new PorterDuffColorFilter(0xffff00,PorterDuff.Mode.MULTIPLY));
and for more you could refer to :
How to change colors of a Drawable in Android?
Change drawable color programmatically
Android: Change Shape Color in runtime
http://pastebin.com/Hd2aU4XC
You could also try this :
private static final int[] FROM_COLOR = new int[]{49, 179, 110};
private static final int THRESHOLD = 3;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.test_colors);
ImageView iv = (ImageView) findViewById(R.id.img);
Drawable d = getResources().getDrawable(RES);
iv.setImageDrawable(adjust(d));
}
private Drawable adjust(Drawable d)
{
int to = Color.RED;
//Need to copy to ensure that the bitmap is mutable.
Bitmap src = ((BitmapDrawable) d).getBitmap();
Bitmap bitmap = src.copy(Bitmap.Config.ARGB_8888, true);
for(int x = 0;x < bitmap.getWidth();x++)
for(int y = 0;y < bitmap.getHeight();y++)
if(match(bitmap.getPixel(x, y)))
bitmap.setPixel(x, y, to);
return new BitmapDrawable(bitmap);
}
private boolean match(int pixel)
{
//There may be a better way to match, but I wanted to do a comparison ignoring
//transparency, so I couldn't just do a direct integer compare.
return Math.abs(Color.red(pixel) - FROM_COLOR[0]) < THRESHOLD && Math.abs(Color.green(pixel) - FROM_COLOR[1]) < THRESHOLD && Math.abs(Color.blue(pixel) - FROM_COLOR[2]) < THRESHOLD;
}
as given in How to change colors of a Drawable in Android?
The following works great for setting the color of the drawable programmatically without changing its shape:
parentLayout.getBackground().setColorFilter(
Color.BLACK,
PorterDuff.Mode.SRC_ATOP
);
use this..
<solid android:color="#e1e1e1" />
<stroke
android:width="2dp"
android:color="#808080" />
<corners android:radius="10dp" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
Also possible way is to use:
val layerDrawable : LayerDrawable = imageView.background as LayerDrawable
val bgShape = layerDrawable.findDrawableByLayerId(R.id.shape_id) as GradientDrawable
bgShape.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
with example (drawable/circle.xml):
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/shape_id">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="1000dp" />
<solid android:color="#F4B528" />
<padding
android:bottom="4dp"
android:left="4dp"
android:right="4dp"
android:top="4dp" />
</shape>
</item>
</layer-list>
and ImageView:
<ImageView
android:id="#+id/imageView"
android:layout_width="16dp"
android:layout_height="16dp"
android:background="#drawable/circle"
/>
One approach would be to create a second drawable XML with the 2nd color and then change the background of the layout with the 2nd drawable.