I'm having a little trouble getting an animated loading spinner to work for a splash page. Nothing shows up when I try to run the following code. Any suggestions? It seems that quite a few people have issues with this on google but I do not understand why mine is failing to work. Thanks!
animationloader.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="#drawable/loadingspinner1" android:duration="200" />
<item android:drawable="#drawable/loadingspinner2" android:duration="200" />
<item android:drawable="#drawable/loadingspinner3" android:duration="200" />
<item android:drawable="#drawable/loadingspinner4" android:duration="200" />
<item android:drawable="#drawable/loadingspinner5" android:duration="200" />
<item android:drawable="#drawable/loadingspinner6" android:duration="200" />
<item android:drawable="#drawable/loadingspinner7" android:duration="200" />
<item android:drawable="#drawable/loadingspinner8" android:duration="200" />
<item android:drawable="#drawable/loadingspinner9" android:duration="200" />
<item android:drawable="#drawable/loadingspinner01" android:duration="200" />
<item android:drawable="#drawable/loadingspinner11" android:duration="200" />
<item android:drawable="#drawable/loadingspinner12" android:duration="200" />
</animation-list>
SplashScreen.java
package com.secure.inmatecanteen;
import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.widget.ImageView;
public class SplashScreen extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splashscreen);
//Beginning the loading animation as we attempt to verify registration with SIP
ImageView ivLoader = (ImageView) findViewById(R.id.IVloadinganimation);
ivLoader.setBackgroundResource(R.anim.animationloader);
AnimationDrawable frameAnimation = (AnimationDrawable) ivLoader.getBackground();
frameAnimation.start();
}
}
splashscreen.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:background="#android:color/white" >
<ImageView
android:id="#+id/iclogo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="#drawable/iclogo"
android:adjustViewBounds="true"
/>
<ImageView
android:id="#+id/IVloadinganimation"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true"
/>
</LinearLayout>
Solved my own problem, You cannot start animations in the oncreate. It has to be in an onclick listener or inside a runnable.
I think the most elegant and versatile option is to extend from the ImageView class:
public class Loader extends ImageView {
public Loader(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public Loader(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Loader(Context context) {
super(context);
init();
}
private void init() {
setBackgroundResource(R.drawable.loader);
final AnimationDrawable frameAnimation = (AnimationDrawable) getBackground();
post(new Runnable(){
public void run(){
frameAnimation.start();
}
});
}
}
The loader.xml located in the drawable folder:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:drawable="#drawable/loader_1" android:duration="50" />
<item android:drawable="#drawable/loader_2" android:duration="50" />
<item android:drawable="#drawable/loader_3" android:duration="50" />
<item android:drawable="#drawable/loader_4" android:duration="50" />
.....
</animation-list>
Now include in your views something as simple as this:
<com.yourpackage.Loader
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
You can play/start animation from onWindowFocusChanged(boolean hasFocus) method.
Don't set image resource in xml code.
My XML is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:gravity="center"
android:keepScreenOn="true"
android:id="#+id/splashLayout"
android:background="#color/colorPrimary"
android:layout_height="match_parent">
<ImageView
android:layout_width="230dp"
android:layout_height="230dp"
android:id="#+id/iv_splash"
android:layout_marginTop="-80dp"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
In Activity i do
public class SplashActivity extends Activity {
ImageView iv_splash;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
iv_splash=(ImageView)findViewById(R.id.iv_splash);
iv_splash.setBackgroundResource(R.drawable.splash);
final AnimationDrawable progressAnimation =(AnimationDrawable)iv_splash.getBackground();
progressAnimation.start();
}
}
Drawable file
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false" >
<item android:drawable="#drawable/logo" android:duration="400"/>
<item android:drawable="#drawable/logo1" android:duration="400"/>
</animation-list>
It's Working Good :)
Within this handler the animation is not fully attached to the window, so the animations can’t be started; instead, this is usually done as a result to user action (such as a button press) or within the onWindowFocusChangedhandler.
refer: professional android 4 application development
Check GitHub project here I have implemented: Check here
My MainActivity.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#color/colorPrimaryDark"
tools:context=".MainActivity">
<ImageView
android:id="#+id/animation_imageview"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerHorizontal="true"
android:src="#drawable/animation_frame"
android:scaleType="fitCenter"
android:layout_marginBottom="50dp"/>
<TextView
android:layout_below="#+id/animation_imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#fff"
android:fontFamily="sans-serif-thin"
android:text="Converting Please wait..."/>
</RelativeLayout>
My animation-list in drawable
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="#drawable/ic_covert_f1" android:duration="90"/>
<item android:drawable="#drawable/ic_covert_f2" android:duration="90"/>
<item android:drawable="#drawable/ic_covert_f3" android:duration="90"/>
<item android:drawable="#drawable/ic_covert_f4" android:duration="90"/>
<item android:drawable="#drawable/ic_covert_f5" android:duration="90"/>
<item android:drawable="#drawable/ic_covert_f6" android:duration="90"/>
<item android:drawable="#drawable/ic_covert_f7" android:duration="90"/>
<item android:drawable="#drawable/ic_covert_f8" android:duration="90"/>
<item android:drawable="#drawable/ic_covert_f9" android:duration="90"/>
<item android:drawable="#drawable/ic_covert_f10" android:duration="90"/>
<item android:drawable="#drawable/ic_covert_f11" android:duration="90"/>
</animation-list>
My MainActivty.java
Always remember to use Runnable to start the animation
public class MainActivity extends AppCompatActivity {
AnimationDrawable progressAnimation;
ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView)findViewById(R.id.animation_imageview);
progressAnimation = (AnimationDrawable)imageView.getDrawable();
progressAnimation.setCallback(imageView);
progressAnimation.setVisible(true, true);
imageView.post(new Starter());
}
class Starter implements Runnable {
public void run() {
progressAnimation.start();
}
}
}
Works Perfectly Good Luck :)
Elegant solution - create your own Animated View which will follow life-cycle rules.
public class AnimatedImageView extends android.support.v7.widget.AppCompatImageView {
public AnimatedImageView(Context context, AttributeSet attrs) {
super(context, attrs);
setImageDrawable(ContextCompat.getDrawable(
context, R.drawable.animated_icon));
}
#Override
protected void onAttachedToWindow() {
// It's important to note that the start() method called on
// the AnimationDrawable cannot be called during the onCreate()
// method of your Activity, because the AnimationDrawable
// is not yet fully attached to the window.
super.onAttachedToWindow();
AnimationDrawable tapAnimation = (AnimationDrawable) getDrawable();
tapAnimation.start();
}
}
here is animated_icon.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="#drawable/tap_icon_1" android:duration="500" />
<item android:drawable="#drawable/tap_icon_2" android:duration="500" />
</animation-list>
Related
Use Selector as view's background, like following codes :
my_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true" android:drawable="#drawable/cell_bg_e" />
<item android:state_checked="true" android:drawable="#drawable/cell_bg_e" />
<item android:state_selected="true" android:drawable="#drawable/cell_bg_e" />
<item android:drawable="#drawable/cell_bg_n_trans" />
</selector>
MyView.java
public class MyView extends LinearLayout
{
public MyView(Context context, CharSequence text, Drawable drawable) {
super(context);
setBackgroundResource(R.drawable.my_selector);
}
}
it works on all the devices except for some certain 800x480 resolution device(lick htc g12)
why ?
You should ensure the view you have set this selector drawable as a background of is clickable.
You can do this in code:
public MyView(Context context, CharSequence text, Drawable drawable) {
super(context);
setClickable(true);
setBackgroundResource(R.drawable.my_selector);
}
Alternatively in XML:
<MyView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/my_selector"
android:clickable="true"
android:orientation="horizontal"/>
I have created a custom Loading Progress Dialog. And its working well.
I am rotating 12 square Images here is one of them
But when I want to use it with AsynTask, The animation not working.
My Sample code is below.
Activity Where I Start Loading... Animation and Stop.
MainActivity.java
public class MainActivity extends Activity {
AnimationDrawable loadingViewAnim;
TextView loadigText;
ImageView loadigIcon;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadigText = (TextView) findViewById(R.id.textView1);
loadigText.setText("Loading...");
loadigText.setVisibility(View.GONE);
loadigIcon = (ImageView) findViewById(R.id.imageView1);
loadigIcon.setVisibility(View.GONE);
loadigIcon.setBackgroundResource(R.anim.progress_animation_white);
loadingViewAnim = (AnimationDrawable) loadigIcon.getBackground();
}
//When User Touch on Screen The Loading... Animation Starts With Image Rotation
//If I start below code in AsynTask's onPreExecute method it doesn't work
public boolean onTouchEvent(MotionEvent event)
{
loadigText.setVisibility(View.VISIBLE);
loadigIcon.setVisibility(View.VISIBLE);
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
loadingViewAnim.start();
return true;
}
return super.onTouchEvent(event);
}
}
XML layout with Simple Text and Image for Progress Dialog.
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/LinearLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#000000"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/progress_sm_w01" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Loading..."
android:textColor="#ffffff"
android:textSize="12sp" />
</LinearLayout>
Animation List having 12 Images I am Rotating with Angle & Time Duration
progress_animation_white.xml
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/progress_sm_w01" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w02" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w03" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w04" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w05" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w06" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w07" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w08" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w09" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w10" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w11" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w12" android:duration="50" />
</animation-list>
Here is the result Loading Screen..
My Question is Is there anyway to Achieve the same Loading Animation
with AsynTask.
Your Small Help will appreciated.
Well thanks to #Brontok and #URAndroid for their help. I got solved my problem.
So let me answer my own question, Hoe i achieved that Custom Loading animation
I have added few Image for Image Rotation Animation
Step 1 - in res/drawable folder
progress_sm_w00.png (Default blank transparent image)
progress_sm_w01.png (first animtion position)
progress_sm_w02.png
progress_sm_w03.png
progress_sm_w04.png
progress_sm_w05.png
progress_sm_w06.png
progress_sm_w07.png
progress_sm_w08.png
progress_sm_w09.png
progress_sm_w10.png
progress_sm_w11.png
progress_sm_w12.png (last animation position).
Example : one of these is below i have added
Step 2 - in res/anim folder created animation file name "loading_animation.xml"
<item android:drawable="#drawable/progress_sm_w01" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w02" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w03" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w04" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w05" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w06" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w07" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w08" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w09" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w10" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w11" android:duration="50" />
<item android:drawable="#drawable/progress_sm_w12" android:duration="50" />
</animation-list>
Step 3 - now created Custom Loading View layout in my Screen (Activity) wherever I need to show loading
example.
XML layout for my Facebook login screen
<LinearLayout
android:id="#+id/LinearLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#0D000000"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone" >
<ImageView
android:id="#+id/imageView111"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/progress_sm_w00"
android:visibility="gone" />
<TextView
android:id="#+id/textView111"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Searching..."
android:textColor="#ffffff"
android:textSize="12sp"
android:visibility="gone" />
</LinearLayout>
Step 4 - In java code (Activity) I created Loading view and after completing OnCreate method I started Asyn Task so my Animation get work properly.
public class ResultActivity extends Activity {
private static final String TAG = "ResultActivity";
private AnimationDrawable loadingViewAnim=null;
private TextView loadigText = null;
private ImageView loadigIcon = null;
private LinearLayout loadingLayout = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
loadingLayout = (LinearLayout)findViewById(R.id.LinearLayout1);
loadingLayout.setVisibility(View.GONE);
loadigText = (TextView) findViewById(R.id.textView111);
loadigText.setVisibility(View.GONE);
loadigIcon = (ImageView) findViewById(R.id.imageView111);
loadigIcon.setVisibility(View.GONE);
loadigIcon.setBackgroundResource(R.anim.loading_animation);
loadingViewAnim = (AnimationDrawable) loadigIcon.getBackground();
// This line is to start Asyn Task only when OnCreate Method get completed, So Loading Icon Rotation Animation work properly
loadigIcon.post(new Starter());
}
class Starter implements Runnable {
public void run() {
//start Asyn Task here
new LongOperation().execute("");
}
}
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
//ToDo your Network Job/Request etc. here
return "Executed";
}
#Override
protected void onPostExecute(String result) {
//ToDo with result you got from Task
//Stop Loading Animation
loadingLayout.setVisibility(View.GONE);
loadigText.setVisibility(View.GONE);
loadigIcon.setVisibility(View.GONE);
loadingViewAnim.stop();
}
#Override
protected void onPreExecute() {
//Start Loading Animation
loadingLayout.setVisibility(View.VISIBLE);
loadigText.setVisibility(View.VISIBLE);
loadigIcon.setVisibility(View.VISIBLE);
loadingViewAnim.start();
}
#Override
protected void onProgressUpdate(Void... values) {}
}
}
Step 5 - Here is the Result Screen with Progress Loading animation.
Hope this will help you. Cheers!!
Maybe you can use GLIDE, for example
Glide.with(context)
.load(imageUrl)
.asGif()
.placeholder(R.drawable.loading2)
.crossFade()
.into(imageView);
Show GIF file with Glide (image loading and caching library)
I have a simple program which is able to change the background color after clicking a button, but it does not work
public class ChangeBackgroundActivity extends Activity {
/** Called when the activity is first created. */
Button blueButton;
LinearLayout myLO;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myLO=(LinearLayout)findViewById(R.layout.main);
blueButton=(Button)findViewById(R.id.button1);
blueButton.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// TODO Auto-generated method stub
myLO.setBackgroundColor(0x0000FF); //blue color code #0000FF
}
});
}
}
Try With this,
main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/myLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="64dp"
android:layout_marginTop="71dp"
android:text="changeColor" />
</LinearLayout>
ChangeBackgroundActivity.java
public class ChangeBackgroundActivity extends Activity {
/** Called when the activity is first created. */
Button blueButton;
LinearLayout myLO;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myLO=(LinearLayout)findViewById(R.id.myLayout);
blueButton=(Button)findViewById(R.id.button1);
blueButton.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// TODO Auto-generated method stub
myLO.setBackgroundColor(Color.BLUE);
}
});
}
}
use
myLO=(LinearLayout)findViewById(R.id.main);
insteadof
myLO=(LinearLayout)findViewById(R.layout.main);
your layout must be like that
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
You have to create an xml file(selector file) and put it in drawable folder in res(res->drawable->yourselectorfile.xml. After that set xml file in button's background in your layout file
button_background_selector.xml
<?xml version="1.0" encoding="UTF-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:state_pressed="false" android:drawable="#drawable/your_hover_image" />
<item android:state_focused="true" android:state_pressed="true" android:drawable="#drawable/your_hover_image" />
<item android:state_focused="false" android:state_pressed="true" android:drawable="#drawable/your_hover_image"/>
<item android:drawable="#drawable/your_simple_image" />
</selector>
Now set the above file in button's background.
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#color/grey_text"
android:background="#drawable/button_background_selector"/>
and for changing color use
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:color="#000000" /> <!-- pressed -->
<item android:state_focused="true"
android:color="#000000" /> <!-- focused -->
<item android:color="#FFFFFF" /> <!-- default -->
</selector>
as your button_background_selector.xml
Use this, this worked for me:
YourView.setBackgroundColor(Color.argb(255, 255, 255, 255));
I have textview which I want to change the color when I focus or cliclked it like a link text in web I have try to follow this but it still doesn't work
please help, thanks
this is my java code
public class TextColorActivity extends Activity {
/** Called when the activity is first created. */
ColorStateList cl = null;
private TextView title;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
title = (TextView)findViewById(R.id.hello);
try {
Log.d("test","try");
XmlResourceParser xpp = getResources().getXml(R.drawable.selector_txt);
cl = ColorStateList.createFromXml(getResources(), xpp);
} catch (Exception e) {}
title.setTextColor(cl);
title.setFocusable(true);
title.setClickable(true);
title.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.d("test","click");
}
});
}
this is my selector_txt.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true" android:color="#color/Darkgoldenrod"/>
<item android:state_pressed="true" android:state_enabled="false"
android:color="#color/Darkgreen" />
<item android:state_enabled="false" android:color="#color/Red" />
<item android:color="#color/blue"/>
and this is my main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/hello"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/hello"
android:textSize="30dp"
android:textStyle="bold"
android:duplicateParentState="true"/>
You can also set your color in the xml if you want. Just create a color folder in your res folder and move the xml file there then you can set it via android:textColor="#color/selector_txt"
Regards the problem you're having. Android will always use the first match in a selector. If a TextView is pressed it is also focused. So add android:pressed="false" to your first item or move the line after the pressed status line.
That's the full xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="#color/Red" />
<item android:state_pressed="true" android:color="#color/Darkgreen" />
<item android:state_focused="true" android:color="#color/Darkgoldenrod"/>
<item android:color="#color/blue"/>
</selector>
So I have a ListView and I want to change the color of each items background and text. This ListView is inside a ListFragment. My code inflates the layout in the onCreateView and inflates the layout of each item in the newView.
The android:state_pressed="true" is working fine, whenever I press in one item the background changes to that color. But when selecting an item neither the bg color or text color changes, even though I've defined an item with android:state_selected="true" in the selector.
Edit: I'm using SDK level 11 (Android 3.0) and a Motorola Xoom.
The list fragment layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
The list item layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="25dp"
android:background="#drawable/list_item_bg_selector">
<TextView android:id="#+id/form_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="#dimen/text_size_xlarge"
android:textStyle="bold"
android:textColor="#drawable/list_item_text_selector" />
<TextView android:id="#+id/form_subtitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="#dimen/text_size_medium"
android:textStyle="normal"
android:layout_marginTop="5dp"
android:textColor="#drawable/list_item_text_selector" />
</LinearLayout>
The background selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="true"
android:drawable="#color/white" />
<item
android:state_selected="true"
android:drawable="#drawable/list_item_bg_selected" />
<item
android:drawable="#color/list_bg" />
</selector>
The text selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_selected="true"
android:drawable="#color/white" />
<item
android:drawable="#color/list_text_blue" />
</selector>
The answer is to use the android:state_activated="true" state, instead of the "selected" state. More on this here: ListFragment Item Selected Background
The best solution with support of all API levels is to implement Checkable feature for list item View which means that the top view of your list item layout has to implement Checkable interface (in my case it was TextView, but the same can be applied on ViewGroup classes like LinearLayout). When you click on a list item, the ListView call setChecked method and there we change the state of View to use android:state_checked="true" selector. Together with list view android:choiceMode="singleChoice" it will select only one item.
The trick is to override onCreateDrawableState method and set the checked state here for drawables. See example of SelectableTextView bellow. After the setChecked is called, the checked state is stored and called refreshDrawableState.
Example of SelectableTextView:
package com.example.widget.SelectableTextView;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.Checkable;
import android.widget.TextView;
public class SelectableTextView extends TextView implements Checkable {
private static final int[] CHECKED_STATE_SET = {
android.R.attr.state_checked
};
private boolean mChecked;
public SelectableTextView(Context context) {
super(context);
}
public SelectableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
public void setChecked(boolean checked) {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
}
}
#Override
public boolean isChecked() {
return mChecked;
}
#Override
public void toggle() {
setSelected(!mChecked);
}
#Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
}
Example of selectable_list_item.xml layout:
<?xml version="1.0" encoding="utf-8"?>
<com.example.widget.SelectableTextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#color/list_item_selector_foreground"
android:background="#drawable/list_item_selector_background"
tools:text="Item 1"/>
Example of list_item_selector_foreground.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- checked -->
<item android:color="#color/list_item_text_active" android:state_checked="true"/>
<item android:color="#color/list_item_text"/>
</selector>
Example of list_item_selector_background.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/list_item_background_selected" android:state_pressed="true"/>
<item android:drawable="#color/list_item_background_selected" android:state_focused="true"/>
<item android:drawable="#color/list_item_background_active" android:state_checked="true"/>
<item android:drawable="#color/list_item_background"/>
</selector>
Do not forget to set clickable="true" for the layout. This solved my problem.
List item layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/list_item_bg_selector"
android:clickable="true" >
<TextView
android:id="#+id/tvNewsPreviewTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="3"
android:ellipsize="end"
android:textSize="#dimen/news_preview_title_textsize"
android:textStyle="bold" />
</RelativeLayout>
Background selector:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" >
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="#color/black" />
<gradient android:startColor="#color/white" android:endColor="#color/white" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="#color/holo_gray_darker" />
<gradient android:startColor="#color/holo_gray_bright" android:endColor="#color/holo_gray_bright" />
</shape>
</item>
</selector>
#Andrew S: Along with using activated state in selector , activated state must be set to false for default case as shown in below selector code.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false"
android:state_activated="false"
android:color="#color/dark_text_blue"/>
<item android:state_pressed="true"
android:color="#color/red"/>
<item android:state_activated="true"
android:color="#color/red"/>
</selector>