Transition Drawable with more than 2 layers - android

Can there be more than 2 items in transition drawable? I need to change background so second frames fades in than on top of it third does and so on to fourth...
for now I have this:
<?xml version="1.0" encoding="UTF-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/voting_button_not1"/>
<item android:drawable="#drawable/voting_button_not2"/>
<item android:drawable="#drawable/voting_button_not3"/>
<item android:drawable="#drawable/voting_button_not4"/>
<item android:drawable="#drawable/voting_button_not5"/>
<item android:drawable="#drawable/voting_button_not1"/>
</transition>
And I got the button:
<ImageButton android:id="#+id/skipButton"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/coldf1f2"
android:scaleType="fitCenter"
android:adjustViewBounds="true"/>
P.S. never mind that its an ImageButton, that doesn't make any difference.
And in my code I got smth like this:
TransitionDrawable vote_not = (TransitionDrawable)skip.getBackground();
vote_not.startTransition(1000);
It plays transition from first item to second. But I need the full list be played.

It seems like TransitionDrawable is meant to operate only with two layers. Taken from the Android documentation for the class:
An extension of LayerDrawables that is intended to cross-fade between
the first and second layer.
I think you can specify more than two layers, because this is extension of layered drawable, but in the case of the TransitionDrawable actually only the first two are used.

you can try this option using a handler
mAnimateImage is a imageView
and DrawableImage is an array with drawables
int DrawableImage[] = {R.drawable.back_red , R.drawable.back_green, R.drawable.back_purple};
final Handler handler = new Handler();
final int[] i = {0};
final int[] j = {1};
handler.postDelayed(new Runnable() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
Resources res = getApplicationContext().getResources();
TransitionDrawable out = new TransitionDrawable(new Drawable[]{res.getDrawable(DrawableImage[i[0]]), res.getDrawable(DrawableImage[j[0]])});
out.setCrossFadeEnabled(true);
mAnimateImage.setImageDrawable(out);
out.startTransition(4000);
i[0]++;
j[0]++;
if (j[0] == DrawableImage.length) {
j[0] = 0;
}
if (i[0] == DrawableImage.length) {
i[0] = 0;
}
handler.postDelayed(this, 8000);
}
});
}
}, 0);

You can do this with a combination of using a Handler and re-applying the TransitionDrawable for the elements of the array.
See my answer at https://stackoverflow.com/a/54584103/114549

Sounds like you might want AnimationDrawable:
http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

Related

what to use if i have long updating ui thread in android

I have a project which a activity have more than 1000 buttons. i am updating the background color of these buttons after taking the color information from the database. This whole process is a very big process and took 8 seconds to load my activity.
i have implement Asynctask for that but the problem is with this exception because "Only the original thread that created a view hierarchy can touch its views". because my long operation is on that part where i am updating my UI elements
After that i have implemented a thread that runs on UIthread for updating ui elements, this works fine according to its function, this thread update my ui but it stucks my application for 5-6 seconds. and then i thought of implementing a progress dialog for that 5-6 seconds. but if i implement progress dialog on runOnUiThread(new Runnable(){} it doesn't work. because updating ui and progress dialog runs on the same time. so progress dialog flashes for few milliseconds. and the activity still remains the same as it was before.
I don't know that to use for updating ui if they took long time to update.
This is my code where i update by ui elements from database.
for (int i = 0; i < list.size(); i++) {
Button btn = list.get(i);
Platform p = db.setplatformncolor(btn.getTag().toString());
String color = p.getColor();
if (color.equals("red")) {
btn.setBackgroundColor(Color.RED);
}
if (color.equals("green")) {
btn.setBackgroundColor(Color.rgb(0, 176, 80));
}
Any help is appreciated.
Thanks.!!
the for loop take two long time, try to just put the loop in thread and setBackgroundColor in ui thread.
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < list.size(); i++) {
final Button btn = list.get(i);
Platform p = db.setplatformncolor(btn.getTag().toString());
String color = p.getColor();
if (color.equals("red")) {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setBackgroundColor(Color.RED);
}
});
}
if (color.equals("green")) {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setBackgroundColor(Color.rgb(0, 176, 80));
}
});
}
}
}
}).start();
You can declare a green button theme and a red button theme like this
<style name="RedButton" parent="#android:style/Widget.Button">
<item name="android:background">#android:color/holo_red_light</item>
</style>
<style name="GreenButton" parent="#android:style/Widget.Button">
<item name="android:background">#android:color/holo_green_light</item>
</style>
Then just apply the theme. The system will automatically apply your background color for all buttons. See here if want more details about themes switching.
AsyncTask can fix your problem. the most time consuming operation in this code is
db.setplatformncolor(btn.getTag().toString());
so you have to move this line into doInBackground() method and after adding to DB call publishProgress() also you should implement onProgressUpdate() and change your button backgrounds in this method
this might be a bit tricky and complex solution for starters , but is efficient and applicable to your requirement.
Android has launched DataBinding Library, which will update your XML dynamically , try it
https://developer.android.com/topic/libraries/data-binding/index.html
If your app api level >=11 and if you only need two colors, then you can create a drawable xml for your buttons' background like:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/red" android:state_activated="false" />
<item android:drawable="#color/green" android:state_activated="true"/>
and then just change btn.setActivated(true/false);

Change TapDown Color on ListView

I have a list view and when the user taps down on the item it looks like this.
This is what it looks like noramally:
How do I change this default light blue color?
I need the color to be set programatically in the activity file, as it is not always the same color, and also how do you change the color of the fuzzy stuff that comes up at the bottom of a ListView when you continue to scroll down?
Thanks for the help
EDIT
Also how do you change the tap down color of the action bar back button,
For the row color, you need to create a StateListDrawable and set it as the selector for the ListView.
The states to include should be, at least:
pressed (android.R.attr.state_pressed)
selected (android.R.attr.state_selected)
"normal" (empty state list)
For each state you can set any drawable. If what you need is a plain color, you can programmatically create a ColorDrawable on the spot.
For example:
StateListDrawable selector = new StateListDrawable();
ColorDrawable red = new ColorDrawable(Color.RED);
ColorDrawable transparent = new ColorDrawable(Color.TRANSPARENT);
selector.addState(new int[] { android.R.attr.state_pressed }, red);
selector.addState(new int[] { android.R.attr.state_selected }, red);
selector.addState(new int[] { }, transparent);
listView.setSelector(selector);
As for the "fuzzy stuff that comes up at the bottom", it's slightly more complicated.
Prior to Android 5.0 there was no public API for changing it.
In Lollipop it can be set via the theme, but not programmatically.
For pre-5.0 there is a well-known workaround (described here) which involves tampering with the drawables that are used. However this solution crashes in 5.0, because those resources do not exist anymore.
For Android 5.0, if a static color is acceptable, you can just configure the new theme attribute android:colorEdgeEffect (which is the same as android:colorPrimary by default).
If a programmatic solution for Android 5.0 is necessary, you could alternatively change the EdgeEffect objects that the ListView has internally using reflection. I've tested this and it works, though it's not the prettiest code:
EdgeEffect edgeEffectTop = new EdgeEffect(this);
edgeEffectTop.setColor(Color.RED);
EdgeEffect edgeEffectBottom = new EdgeEffect(this);
edgeEffectBottom.setColor(Color.RED);
try {
Field f1 = AbsListView.class.getDeclaredField("mEdgeGlowTop");
f1.setAccessible(true);
f1.set(listView, edgeEffectTop);
Field f2 = AbsListView.class.getDeclaredField("mEdgeGlowBottom");
f2.setAccessible(true);
f2.set(listView, edgeEffectBottom);
} catch (Exception e) {
e.printStackTrace();
}
Therefore, a full programmatic solution may run something like this:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
// For Android >= 5.0, use setColor() on EdgeEffect
EdgeEffect edgeEffectTop = new EdgeEffect(this);
edgeEffectTop.setColor(Color.RED);
EdgeEffect edgeEffectBottom = new EdgeEffect(this);
edgeEffectBottom.setColor(Color.RED);
try {
Field f1 = AbsListView.class.getDeclaredField("mEdgeGlowTop");
f1.setAccessible(true);
f1.set(listView, edgeEffectTop);
Field f2 = AbsListView.class.getDeclaredField("mEdgeGlowBottom");
f2.setAccessible(true);
f2.set(listView, edgeEffectBottom);
} catch (Exception e) {
e.printStackTrace();
}
}
else
{
// For Android < 5.0, change overscroll_glow and overscroll_edge
int glowDrawableId = getResources().getIdentifier("overscroll_glow", "drawable", "android");
Drawable androidGlow = getResources().getDrawable(glowDrawableId);
androidGlow.setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY);
int edgeDrawableId = getResources().getIdentifier("overscroll_edge", "drawable", "android");
Drawable androidEdge = getResources().getDrawable(edgeDrawableId);
androidEdge.setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY);
}
How do I change this default light blue color?
you have to create StateListDrawable and set it as the selector for the ListView. the answer of matiash is good and I do not want to explain it again.
change the color of the fuzzy stuff that comes up at the bottom of a
ListView when you continue to scroll down
setCacheColorHint (int color)
Also how do you change the tap down color of the action bar back
button
<style name="actionbarCustomBackground" parent="#style/Theme.Holo.Light" >
<item name="android:selectableItemBackground">#drawable/actionbar_item_background</item>
</style>
then in the actionbar_item_background:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="#android:integer/config_mediumAnimTime">
<item
android:state_focused="true"
android:state_pressed="true"
android:drawable="#android:color/holo_orange_dark" />
<item
android:state_pressed="true"
android:drawable="#android:color/holo_orange_dark" />
<item
android:drawable="#android:color/transparent" />
</selector>
You can set row's background dynamically in getView(..) method.
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
.......... //your code
view.setBackgroundColor(Color.RED)
return view;
}

gradual button color change on android

I want gradually change button color, after click on it. I mean, button must have, for example next set of colors: by default - dark dark blue, then dark blue, then blue, then light blue, and in the end - the lightest blue. This is only example, really I want to change button color in cycle, like in the next code. But, I can't understand, why it doesn't show intermediate colors. It shows only first color, and the last one.
How to improve this?
public class ActivityExample extends Activity {
private changeColorBtn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_animations);
changeColorBtn = (Button) findViewById(R.id.btn_change_color);
changeColorBtn.setBackgroundColor(Color.BLACK);
changeColorBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
changeButtonColor(v);
}
});
}
private void changeButtonColor(View v) {
// How many intermediate color will be, and delay in millisecond between them
int count = 20, delay = 100;
for (int i = 0; i < count; i++) {
try {
int color = ((ColorDrawable) changeColorBtn.getBackground())
.getColor();
int blue = Color.blue(color), red = Color.red(color), green = Color.green(color);
changeColorBtn.setBackgroundColor(Color.rgb(red+10, green+5, blue+3));
Thread.sleep(delay);
} catch (InterruptedException inE) {
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
I solved this problem using TransitionDrawable. You can follow next step:
Create an xml file in the drawable folder, and write there something like:
`
<?xml version="1.0" encoding="UTF-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/color1" />
<item android:drawable="#color/color2" />
</transition>
`
Then, in your xml for this button (or another element / View) you should reference this TransitionDrawable in the android:background attribute.
Also you should have colors stored as resources: for this, you have to create an xml like following:
`
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<color name="color1">#990000</color>
<color name="color2">#cc3311</color>
</resources>
`
and save this xml file in the /res/values/ folder, name the xml as color.xml.
And initiate the transition in code:
`
int durationMillis = 2000;
TransitionDrawable transition = (TransitionDrawable) changeColorBtn.getBackground();
transition.startTransition(durationMillis);
`
This is helped me, I hope it will be useful for others.

Android: Is it possible to use string/enum in drawable selector?

Questions
Q1: Has anyone managed to get custom string/enum attribute working in xml selectors? I got a boolean attribute working by following [1], but not a string attribute.
EDIT: Thanks for answers. Currently android supports only boolean selectors. See accepted answer for the reason.
I'm planning to implement a little complex custom button, whose appearance depends on two variables. Other will be a boolean attribute (true or false) and another category-like attribute (has many different possible values). My plan is to use boolean and string (or maybe enum?) attributes. I was hoping I could define the UI in xml selector using boolean and string attribute.
Q2: Why in [1] the onCreateDrawableState(), boolean attributes are merged only if they are true?
This is what I tested, boolean attribute works, string doesn't
NOTE: This is just a test app to figure out if string/enum attribute is possible in xml selector. I know that I could set button's textcolor without a custom attribute.
In my demo application, I use a boolean attribute to set button background to dark/bright and string attribute to set text color, one of {"red", "green", "blue"}. Attributes are defined in /res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomButton">
<attr name="make_dark_background" format="boolean" />
<attr name="str_attr" format="string" />
</declare-styleable>
</resources>
Here are the selectors I want to achieve:
#drawable/custom_button_background (which works)
<?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/com.example.customstringattribute">
<item app:make_dark_background="true" android:drawable="#color/dark" />
<item android:drawable="#color/bright" />
</selector>
#color/custom_button_text_color (which does not work)
<selector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.customstringattribute">
<item app:str_attr="red" android:color="#color/red" />
<item app:str_attr="green" android:color="#color/green" />
<item app:str_attr="blue" android:color="#color/blue" />
<item android:color="#color/grey" />
</selector>
Here is how custom button background is connected to boolean selector, and text color is connected to string selector.
<com.example.customstringattribute.MyCustomButton
...
android:background="#drawable/custom_button_background"
android:textColor="#color/custom_button_text_color"
...
/>
Here is how attributes are loaded in the init() method:
private void init(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.MyCustomButton);
final int N = a.getIndexCount();
for (int i = 0; i < N; ++i)
{
int attr = a.getIndex(i);
switch (attr)
{
case R.styleable.MyCustomButton_str_attr:
mStrAttr = a.getString(attr);
break;
case R.styleable.MyCustomButton_make_dark_background:
mMakeDarkBg = a.getBoolean(attr, false);
break;
}
}
a.recycle();
}
I have the int[] arrays for the attributes
private static final int[] MAKE_DARK_BG_SET = { R.attr.make_dark_background };
private static final int[] STR_ATTR_ID = { R.attr.str_attr };
And those int[] arrays are merged to drawable state
#Override
protected int[] onCreateDrawableState(int extraSpace) {
Log.i(TAG, "onCreateDrawableState()");
final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
if(mMakeDarkBg){
mergeDrawableStates(drawableState, MAKE_DARK_BG_SET);
}
mergeDrawableStates(drawableState, STR_ATTR_ID);
return drawableState;
}
I also have refreshDrawableState() in my attribute setter methods:
public void setMakeDarkBg(boolean makeDarkBg) {
if(mMakeDarkBg != makeDarkBg){
mMakeDarkBg = makeDarkBg;
refreshDrawableState();
}
}
public void setStrAttr(String str) {
if(mStrAttr != str){
mStrAttr = str;
refreshDrawableState();
}
}
[1] : How to add a custom button state
Q1:
When you open the source-code of StateListDrawable.java, you can see this piece of code in the inflate method that reads the drawable xml selector:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/graphics/java/android/graphics/drawable/StateListDrawable.java
...
for (i = 0; i < numAttrs; i++) {
final int stateResId = attrs.getAttributeNameResource(i);
if (stateResId == 0) break;
if (stateResId == com.android.internal.R.attr.drawable) {
drawableRes = attrs.getAttributeResourceValue(i, 0);
} else {
states[j++] = attrs.getAttributeBooleanValue(i, false)
? stateResId
: -stateResId;
}
}
...
attrs are the attributes of each <item> element in the <selector>.
In this for-loop it gets the android:drawable, the various android:state_xxxx and custom app:xxxx attributes. All but the android:drawable attributes seem to be interpreted as booleans only: attrs.getAttributeBooleanValue(....) is called.
I think this is the answer, based on the source code:
You can only add custom boolean attributes to your xml, not any other type (including enums).
Q2:
I'm not sure why the state is merged only if it is specifically set to true. I would suspect the code should have looked like this instead:
private static final int[] MAKE_DARK_BG_SET = { R.attr.make_dark_background };
private static final int[] NOT_MAKE_DARK_BG_SET = { -R.attr.make_dark_background };
....
....
#Override
protected int[] onCreateDrawableState(int extraSpace) {
Log.i(TAG, "onCreateDrawableState()");
final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
mergeDrawableStates(drawableState, mMakeDarkBg? MAKE_DARK_BG_SET : NOT_MAKE_DARK_BG_SET);
//mergeDrawableStates(drawableState, STR_ATTR_ID);
return drawableState;
}
Q1:
I haven't tried this myself, but:
Have you tried placing your #color/custom_button_text_color.xml in the drawable folder? (Just to be sure, there's a bit of folder magic here and there in Android and I'm not sure about this one.)
Q2:
There are two use cases for state sets. One is to explicitly declare selectors for stateful drawables programmatically. In this case, for selectors, you need to be able to tell Android to use this drawable if an attribute is not set. To express this, you can include the negated criteria (preceded by a minus sign) in the int[].
While this is barely mentioned anywhere in the context of selector criteria, it is never mentioned for drawable states themselves (aka the representation of the drawable's state). So one is definitely on the safe side if one does not include negated state IDs in the set; the provided Android implementations also do not includde them.
Sorry, you cannot create custom drawables in xml :
https://groups.google.com/d/msg/android-developers/glpdi0AdMzI/LpW4HGMB3VIJ

How to make a LayerDrawable (layer-list item) invisible on Android?

I have defined a layer-list with a couple of items on an xml file.
The items are displayed o.k.
I want every five second or so one of the layers to become invisible.
It works o.k. for a simple textview for example but not for the Layer inside the LayerDrawable
final private Runnable runnable = new Runnable() {
public void run() {
LayerDrawable myDrawable= (LayerDrawable)getResources().getDrawable(R.drawable.all_layers);
Drawable layer = myDrawable.findDrawableByLayerId(R.id.interesting_layer);
if (layer.isVisible()==true)
{
layer.setVisible(false, false);
}
else
{
layer.setVisible(true, false);
}
TextView txt = (TextView) findViewById(R.id.txtTest);
if (txt.getVisibility()==0)
{
txt.setVisibility(4);
}
else
{
txt.setVisibility(0);
}
handler.postDelayed(this, 5000);
}
};
Do I try to get the Id of the layer in a wrong way (I found it from here...)?
Thanks in advance!
I did that playing with the alpha of the layer. This code will make your layer disappear:
layer.setAlpha(0);
And then you can display it again with:
layer.setAlpha(255);
Hope this helps.

Categories

Resources