Changing the custom state of a custom StateListDrawable (selector) - android

So I have a custom drawable with selector<> at its root. It uses custom states declared in my attrs.xml:
<declare-styleable name="Status">
<attr name="status_soon" format="boolean"/>
<attr name="status_available" format="boolean"/>
<attr name="status_error" format="boolean"/>
</declare-styleable>
The drawable itself is a simple circle with a solid color (soon = yellow, available = green and error = red, basically).
I have tested individually these layer-lists and they work perfectly fine.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- SOON -->
<item app:status_soon="true">
<layer-list>
<item>
<shape android:shape="oval">
<size android:width="12dp" android:height="12dp" />
<solid android:color="#color/status_soon" />
</shape>
</item>
</layer-list>
</item>
<!-- AVAILABLE -->
<item app:status_available="true">
<layer-list>
<item>
<shape android:shape="oval">
<size android:width="12dp" android:height="12dp" />
<solid android:color="#color/status_available" />
</shape>
</item>
</layer-list>
</item>r-list>
</item>
<!-- ERROR -->
<item app:status_error="true">
<layer-list>
<item>
<shape android:shape="oval">
<size android:width="12dp" android:height="12dp" />
<solid android:color="#color/status_error" />
</shape>
</item>
</layer-list>
</item>
</selector>
Now, my particularity is that I am using this drawable as a compound drawable of a text view.
Example would be: "status: soon + yellow circle"
So I am not using it as a background of my custom view (custom TextView). Because of that I cannot use the usual onCreateDrawableState(extraspace: Int) and refreshDrawableState() functions.
Instead, depending on the status (a simple enum class), I am doing this in my code:
// CustomStatusTextView.kt
private val statusDrawable = ContextCompat.getDrawable(context, R.drawable.status_drawable)
init {
setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, statusDrawable, null)
}
fun setStatus(status: Status) {
when (status) {
Status.SOON -> statusDrawable.state = intArrayOf(R.attr.status_soon)
Status.AVAILABLE -> statusDrawable.state = intArrayOf(R.attr.status_available)
Status.ERROR -> statusDrawable.state = intArrayOf(R.attr.status_error)
}
}
Unfortunately, no drawable is visible at all. What am I doing wrong ?
As stated before, I have tested individually each of the layers of my custom status drawable in order to ensure they actually work.
So, until I find a solution using custom states / attributes, I am going to stick with manually declaring 3 single drawables (one per state - soon, available error) and switching between them depending on the status provided to setStatus(...).
Thanks for the help!

Related

How to create two shapes inside an item drawable?

I am using a custom layout for a progressbar which consist of small bars depending on the count of steps. A layout can be seen below:
I want to create an item that shows a black bar and a white bar which looks like space in between progresses.
Now, I know its possible to create this with two separate item. But I the item as progress of a progressbar. For example:
<!-- Define the progress properties like start color, end color etc -->
<item android:id="#android:id/progress">
<clip>
<shape 1>
<shape 2>
</clip>
</item>
Now, how can I create a custom item that can consist of two shapes inside it?
progress.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="3dp"
android:height="2dp"
android:drawable="#drawable/text_field"
android:start="#dimen/dimen_5dp" />
<item
android:width="3dp"
android:drawable="#drawable/text_field"
android:end="#dimen/dimen_5dp" />
</layer-list>
text_field.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true">
<shape>
<gradient
android:endColor="#color/white"
android:startColor="#color/white"/>
<corners android:radius="5dp"/>
</shape>
</item>
</selector>

Tint VectorDrawable inside Drawable Resource xml

i've had a drawable resource for a selectable Button/ImageView like this:
<selector>
<item android:state_selected="true">
<layer-list>
<item>
<shape android:shape="oval">
<solid android:color="#color/blue"/>
</shape>
</item>
<item>
<bitmap
android:src="#drawable/ic_icon"
android:tint="#color/white"/>
</item>
</layer-list>
</item>
<item>
<layer-list>
<item>
<shape android:shape="oval">
<solid android:color="#color/background_unselected"/>
</shape>
</item>
<item>
<bitmap
android:src="#drawable/ic_icon"
android:tint="#color/icon_unselected"/>
</item>
</layer-list>
</item>
as i've switched to use VectorDrawables the above declaration does not work because i cannot reference a VectorDrawable with a <bitmap> tag.
But as far as i know that's the only way i can tint the icon.
I also cannot apply a Colorfilter in code as this would tint the whole drawable and not just the icon.
Any suggestions?
You can define colors as attributes and reference them in your SVG. Then can load the drawable styled by a theme.
Short example:
attributes.xml
<declare-styleable name="vectorColors">
<attr name="primaryColor" format="color" />
<attr name="secondaryColor" format="color" />
</declare-styleable>
ic_icon.xml
<path
android:fillColor="?attr/primaryColor"
android:pathData="...." />
<path
android:fillColor="?attr/secondaryColor"
android:pathData="...." />
styles.xml
<style name="svgColors">
<item name="primaryColor">#color/someColor</item>
<!-- also can use #RRGGBB way -->
<item name="secondaryColor">#ff0000</item>
</style>
Then load your theme and drawable:
Resources.Theme theme = getResources().newTheme();
theme.applyStyle(R.style.svgColors, false);
VectorDrawableCompat drawable = VectorDrawableCompat.create(getResources(), R.drawable.ic_icon, theme);
imageView.setImageDrawable(drawable);
In your specific selector you should replace
<item>
<bitmap
android:src="#drawable/ic_icon"
android:tint="#color/white"/>
</item>
by <item android:drawable="#drawable/ic_icon">
Reference and full example

How to create the checkBox in circular shape?

I am facing the issue in creating the checkbox in circular shape in android. I tried many methods but my problem is not solved.I created the shapes and applied to the checkbox then also problem is not solved.Please help me how to create the check box in circle shape .
How to create the circular checkbox like shown image.
After spending some time, i have created this template, which you can use. You may need to modify as required.
In activity.xml
<CheckBox
android:id="#+id/checkb"
android:layout_width="115dp"
android:layout_height="50dp"
android:button="#drawable/custom_checkbox"
android:scaleX="3"
android:scaleY="3"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="15dp"
android:layout_marginEnd="15dp" />
create a new xml in drawable folder called custom_checkbox.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="true"
android:drawable="#drawable/checked" />
<item android:state_pressed="true"
android:drawable="#drawable/checked" />
<item android:state_pressed="false"
android:drawable="#drawable/unchecked" />
</selector>
create a new xml in drawable folder called checked.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<layer-list>
<item>
<shape android:shape="oval">
<corners android:radius="1dp" />
<stroke
android:width="1dp"
android:color="#777" />
<gradient
android:startColor="#990000"
android:centerColor="#990000"
android:endColor="#990000"
android:angle="270" />
<size
android:width="30dp"
android:height="30dp" />
</shape>
</item>
<item
android:width="8dp"
android:height="2dp"
android:top="20dp"
android:left="6dp">
<rotate
android:fromDegrees="45">
<shape android:shape="rectangle">
<solid android:color="#fff"/>
</shape>
</rotate>
</item>
<item
android:width="19dp"
android:height="2dp"
android:top="16dp"
android:left="9dp">
<rotate
android:fromDegrees="-45">
<shape android:shape="rectangle">
<solid android:color="#fff"/>
</shape>
</rotate>
</item>
</layer-list>
</item>
</selector>
create a new xml in drawable folder called unchecked.xml
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<corners android:radius="1dp" />
<stroke
android:width="1dp"
android:color="#777" />
<gradient
android:startColor="#990000"
android:centerColor="#990000"
android:endColor="#990000"
android:angle="270" />
<size
android:width="30dp"
android:height="30dp" />
</shape>
When unchecked it looks as below. (you can add the code between from checked.xml and modify the top and left to give X when checkbox is not checked)
When checked it will look as below
If this works mark it as answer.
many of the previous answers are well accepted with chirag90's answer being the best but also need a lot of coding, in my answer i will retake his concept but will show you how you can create your own circular checkbox drawables with all the style you want without any coding needed, you will then use this drawables to defind the states of the checkbox like in chirag90's answer
first go to freelogomaker.com and create your drawables, it is very easy to use and you can create any thing, on the website go to the shape's search bar and type "round checkbox" then click the search button, a list of mutiple drawables will be presented to you so you can choose
above are the drawables i selected, customise as you wish and save then go to appiconmaker.co and use the drawables you created to generate the various design sizes of the drawables like mdpi,hdpi,xhdpi and xxhdpi, below are the drawables i made
unchecked checkbox
checked checkbox
once that is done you can then add the drawables to your project with the coresponding names checked and unchecked in your drawables folder,once all that done now create custom_checkbox.xml like in chirag90's answer
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_checked="true"
android:drawable="#drawable/checked" />
<item android:state_pressed="true"
android:drawable="#drawable/checked" />
<item android:state_pressed="false"
android:drawable="#drawable/unchecked" />
</selector>
now in your layout create your checkbox as follows
<CheckBox
android:id="#+id/checkman"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:layout_marginEnd="15dp"
android:button="#drawable/custom_checkbox"
android:scaleX="0.8"
android:scaleY="0.8" />
you my then modify the android:scaleX="0.8" and android:scaleY="0.8" to fit your layout
this is the result in my project
unchecked
checked
hope this helps many out there
Solution accepted is correct, but following the same flow you can change the shapes to use a drawable on the "checked.xml" this solution should work with android devices before API 21 because there is no width or height on shapes on xml drawables.
Unchecked XML:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:color = "#color/lightgray" />
</shape>
Checked XML:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android = "http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="#color/colorPrimary" />
</shape>
</item>
<item
android:drawable="#drawable/check_arrow_png" />
</layer-list>
All the answers above require creating custom drawables while we can achieve this by using built-in vector drawables.
Have a look at this post it explains this beautifully.
In addition to answer of Rodolfo, I can add, that you can use inset attributes if your drawable is too big.
Note: the solution of #chirag90 works only for API 23 and higher.
Note: vector drawable can be rendered badly.
Checked.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid
android:color="#color/col_chat_selected"/>
<size
android:width="35dp"
android:height="35dp"/>
</shape>
</item>
<item>
<inset
android:drawable="#drawable/shape"
android:insetBottom="10dp"
android:insetLeft="10dp"
android:insetRight="10dp"
android:insetTop="10dp"/>
</item>
</layer-list>
All the proposed options are sheer nonsense, since it is difficult and not beautiful, my solution: learn vector animation and make everything beautiful with ShapeShifter.design
Create TWO animations Start_to_End and End_to_Start;
Export the created animation in the format AnimationVectorDrawable;
Move your animation to the resources folder drawable;
Place ImageView in XML;
For convenience, create CustomImageView { Do not worry below will be an example };
#RequiresApi(Build.VERSION_CODES.M)
class CustomCheckBox(
context: Context,
attrs: AttributeSet
) : AppCompatImageView(context, attrs) {
private val TAG = this::class.simpleName
private val check =
resources.getDrawable(R.drawable.avd_anim_start_to_end)!!.toAnimationVectorDrawable()
private val uncheck =
resources.getDrawable(R.drawable.avd_anim_end_to_start)!!.toAnimationVectorDrawable()
init {
setImageDrawable(check)
setOnClickListener { animateCheckOrUncheck() }
}
private fun animateCheckOrUncheck() {
check.registerAnimationCallback(object : Animatable2.AnimationCallback() {
override fun onAnimationEnd(drawable: Drawable?) {
Log.i(TAG, "onAnimationEnd: check")
check.reset()
setImageDrawable(uncheck)
}
})
uncheck.registerAnimationCallback(object : Animatable2.AnimationCallback() {
override fun onAnimationEnd(drawable: Drawable?) {
Log.i(TAG, "onAnimationEnd: uncheck")
uncheck.reset()
setImageDrawable(check)
}
})
(drawable as AnimatedVectorDrawable).start()
}
}
#RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun Drawable.toAnimationVectorDrawable(): AnimatedVectorDrawable {
return (this as AnimatedVectorDrawable)
}

Create rectangle progress bar in android

Hello, I want to create progress bar which should look like above image. Here, I have created one like below image.
Below is the xml file which I created in drawable folder under res,
progress.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">
<solid android:color="#color/white"/>
</shape>
</item>
<item android:id="#android:id/progress">
<clip>
<shape android:shape="rectangle">
<solid android:color="#color/lightgreen"/>
</shape>
</clip>
</item>
</layer-list>
But I want exactly the same progress bar as image 1 when progress continues, how to implement it?
Customizing a progress bar requires defining the attribute or properties for background and and progress of your progress bar.
create a xml file named customprogressbar.xml in your res-> drawable folder
customprogressbar.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Define the background properties like color etc -->
<item android:id="#android:id/background">
<shape>
<gradient
android:startColor="#000001"
android:centerColor="#0b131e"
android:centerY="1.0"
android:endColor="#0d1522"
android:angle="270"
/>
</shape>
</item>
<!-- Define the progress properties like start color, end color etc -->
<item android:id="#android:id/progress">
<clip>
<shape>
<gradient
android:startColor="#007A00"
android:centerColor="#007A00"
android:centerY="1.0"
android:endColor="#06101d"
android:angle="270"
/>
</shape>
</clip>
</item>
Now you need to set the to set the progressDrawable property to customprogressbar.xml(drawable)
you can do it in xml file or in Activity(at run time)
In your xml do like following
<ProgressBar
android:id="#+id/progressBar1"
style="?android:attr/progressBarStyleHorizontal"
android:progressDrawable="#drawable/custom_progressbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
at runtime do the following
// Get the Drawable custom_progressbar
Drawable draw= res.getDrawable(R.drawable.custom_progressbar);
// set the drawable as progress drawavle
progressBar.setProgressDrawable(draw);
For more details check out HERE
Also check How to Customize ProgressBar in Android?
You need to change xml to mention start-color, end-color and center.
Mention color values properly: start-color: left, end-color: right and center.

android layer-list header and footer

I am trying to create a background drawable for a linearlayout that has multiple gradients.
E.g. I want to have a gradient at the top and bottom, and a solid color in the middle. So basically a header and footer.
I am trying to use a layer-list like this:
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<!--Red-->
<item>
<shape
xmlns:android="http://schemas.android.com/apk/res/android">
<solid
android:color="#ff0000" />
</shape>
</item>
<!-- Green -->
<!-- Offsets from the top and bottom -->
<item
android:top="20dp"
android:bottom="20dp">
<shape
xmlns:android="http://schemas.android.com/apk/res/android">
<solid
android:color="#00ff00" />
</shape>
</item>
<item
android:top="80dp">
<!--Blue -->
<shape
xmlns:android="http://schemas.android.com/apk/res/android">
<solid
android:color="#0000ff" />
</shape>
</item>
</layer-list>
The problem is, I am unsure of the max value of density independant pixels. For this to work, the bottom item offest would need to be (max dp value-20). I have tried to assume the max is 100, and also assume the max is 160 (from the documentation), but neither of these work.
Any ideas?

Categories

Resources