I am trying to create a media player and in that I want to make the Play button transform to Pause button when clicked and again transform back to Play button when clicked again. It's a .gif image which I want to play forward upon first click and play backward upon second click. There are many tutorials about how to add an image as a button in android but none of them talks about button with animation that plays upon clicking. I am sure this is supported because I have seen similar applications. I want to know what is the correct way to do this? So it's not performance expensive and also works correctly regardless of the environment. Also I would appreciate a minimal example if possible.
UPDATE:
As a real close example to what I have in mind can be the Sony Xperia (Z1 or Z Ultra models to be specific) walkman app. This is a sample image to clarify things further.
You could use an AnimationDrawable (link contains example).
I don't see a way to play it in reverse, so you'd probably create 2 of them, one with the images playing forward, one with them playing backward. In your button OnClickListener, set the drawable to one animation or the other as needed, then start() the animation.
To use this technique you'll have to convert your gif into individual frames. There are a good number of free tools you can use to do this.
Example code:
public class AnimationDrawableButtonActivity extends FragmentActivity {
private AnimationDrawable[] mAnimations;
private int mAnimationIndex = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_animation_drawable_button);
new LoadAnimationTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
class LoadAnimationTask extends AsyncTask<Void, Void, AnimationDrawable[]>{
#Override
protected AnimationDrawable[] doInBackground(Void... voids) {
AnimationDrawable[] animations = new AnimationDrawable[2];
animations[0] = (AnimationDrawable) getResources().getDrawable(R.drawable.play_pause);
animations[1] = (AnimationDrawable) getResources().getDrawable(R.drawable.play_pause_reverse);
animations[0].setOneShot(true);
animations[1].setOneShot(true);
return animations;
}
#Override
protected void onPostExecute(AnimationDrawable[] animationDrawables) {
super.onPostExecute(animationDrawables);
mAnimations = animationDrawables;
final ImageButton playButton = (ImageButton) findViewById(R.id.btnPlay);
playButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mAnimationIndex = (mAnimationIndex+ 1) %2;
playButton.setImageDrawable(mAnimations[mAnimationIndex]);
mAnimations[mAnimationIndex].start();
}
});
}
}
}
play_pause.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/play_pause_022" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_023" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_024" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_025" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_026" android:duration="#integer/play_pause_duration" />
</animation-list>
play_pause_reverse.xml
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/play_pause_026" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_025" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_024" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_023" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_022" android:duration="#integer/play_pause_duration" />
</animation-list>
ints.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="play_pause_duration">32</integer>
</resources>
activity_animation_drawable_button.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/btnPlay"
android:layout_gravity="center"
android:src="#drawable/play_pause_022"
style="?android:attr/buttonBarButtonStyle"
android:padding="8dp" />
</FrameLayout>
Related
I have created a frame animations by the code below. I want every time I click at the button the animation will start but it only work at first time.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/frame"
/>
<Button
android:layout_centerInParent="true"
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Animation"
/>
</RelativeLayout>
frame.xml
<animation-list
android:oneshot="true"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<item android:drawable="#drawable/ic_heart_0" android:duration="300" />
<item android:drawable="#drawable/ic_heart_50" android:duration="300" />
<item android:drawable="#drawable/ic_heart_75" android:duration="300" />
<item android:drawable="#drawable/ic_heart_100" android:duration="300" />
<item android:drawable="#drawable/ic_heart_0" android:duration="300" />
</animation-list>
Activity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startAnimation();
}
});
}
public void startAnimation(){
ImageView img = (ImageView) findViewById(R.id.image);
((AnimationDrawable) img.getBackground()).start();
}
}
How can I make the animation can start whenever I click at the Button?
Any help or suggestion would be great appreciated.
You try stop() animation after 300 duration in MainActivity. I think it not recognize either you stop or not maybe. It stop after 300 , right ? but i think maybe app recognize it still start.
Here is one solution that I found. I try to stop animation if it is running before I start it again. I think animation not stop even it have gone through all frame
if(((AnimationDrawable) imageView.getBackground()).isRunning()){
((AnimationDrawable) imageView.getBackground()).stop();
}
((AnimationDrawable) imageView.getBackground()).start();
In order to run "one shot animation" again:
private void runAnimation(ImageView imageView) {
AnimationDrawable animation = (AnimationDrawable) imageView.getBackground();
animation.setVisible(true, true);
animation.start();
}
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)
In my app, I have a blinking play-pause button which I've made using an animation-list, as follows:
<?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/play_pause" android:duration="750" />
<item android:drawable="#drawable/play_pause_play" android:duration="750" />
</animation-list>
Both play_pause and play_pause_play are PNG files. This animation is used (as #drawable/play_pause_ready) inside a level-list:
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:maxLevel="1" android:drawable="#drawable/play_pause_pause" />
<item android:maxLevel="2" android:drawable="#drawable/play_pause_play" />
<item android:maxLevel="3" android:drawable="#drawable/play_pause" />
<item android:maxLevel="10" android:drawable="#drawable/play_pause_ready" />
</level-list>
and the level-list in turn is used as a compound drawable in a TextView. In case it's relevant, the code to operate it looks like this:
private void updatePlayPauseButton(...) {
if (getView() != null) {
LevelListDrawable ld = (LevelListDrawable) timeField.getCompoundDrawables()[2];
ld.setLevel(...);
Drawable child = ld.getCurrent();
if (child instanceof AnimationDrawable) {
AnimationDrawable ad = (AnimationDrawable) child;
ad.start();
}
}
}
and is called from onStart() and other places (the behaviour is the same when it's called in response to a button press).
On ICS and Jellybean, everything works perfectly, but on my HTC Desire running Froyo, the animation displays wrong. The first frame of the animation displays for roughly the right duration (750 ms), but the second frame displays for a very short period, no more than 20 ms.
This looks very much like a bug in Froyo, but I can't find anything about it on Internet. Has anyone seen this problem before, and if so, is there a workaround?
i had similar issues with animation-list on Android 2.2, 3.2
solved with AnimationDrawable.setCallback()
void startAnimation(ImageView iv) {
final AnimationDrawable ad = (AnimationDrawable) iv.getDrawable();
ad.setCallback(iv);
ad.setVisible(true, true);
iv.post(new Runnable() {
#Override public void run() {
ad.start();
}
});
}
I'm working on a project which should have a progressdialog. But since i didn't find an easy way to style a progressdialog, i was thinking, that the easiest way is to create a custom dialog class with it's own style, and a frame by frame animation on it, and show it instead. Here is my code:
The xml layout for the dialog:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/dialog_background"
android:gravity="center"
android:orientation="horizontal"
android:padding="10dp" >
<ImageView
android:id="#+id/loaddialog_animation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/loadanimation"
android:layout_marginRight="10dp" />
<TextView
android:id="#+id/loaddialog_text"
style="#style/SmallText"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Here is my dialog class:
public class LoadDialog extends Dialog
{
private TextView message;
ImageView image;
AnimationDrawable animation;
public LoadDialog(Context context)
{
super(context, R.style.Dialog);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.load_dialog);
message = (TextView) findViewById(R.id.loaddialog_text);
image = (ImageView) findViewById(R.id.loaddialog_animation);
image.setBackgroundResource(R.drawable.loadanimation);
animation = (AnimationDrawable) image.getBackground();
}
public void setText(String msg)
{
message.setText(msg);
}
#Override
public void show()
{
super.show();
animation.start();
}
#Override
public void dismiss()
{
animation.stop();
super.dismiss();
}
}
and the animation resource:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true" >
<item android:drawable="#drawable/loadbar_01" android:duration="50" />
<item android:drawable="#drawable/loadbar_02" android:duration="50" />
<item android:drawable="#drawable/loadbar_03" android:duration="50"/>
</animation-list>
The problem is that the animation doesn't starts, when i try to show it. I know, there are a lots of topics about this problem, but here are the things, that i have tried:
Put the dialogs show() in different parts of my activity: onResume() and onCreate().
onWindowFocusChanged() is not an option, since i want to show a dialog. dialog shown ->focus change, dialog dismissed->focus change ->infinite amount of dialogs shown.
I have tried animation.setCallback(image), animation.setVisible(true, true), animation.invalidateSelf() none of them works.
I have tried image.post() and put a runnable in there as a parameter, and in the run method starting the animation, no luck.
At this point i'm starting to run out of options. The I'm only trying to show 3 images changing until the dialog is dismissed. Please if you know, what am i doing wrong, or any alternative, let me know!
Thanks in advance!
Change android:oneshot="true" to android:oneshot="false" so that it repeats. It should be currently only doing one cycle and since your show time is 50, that is really fast. I would also change that to maybe 200 or so..
<?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/loadbar_01" android:duration="200" />
<item android:drawable="#drawable/loadbar_02" android:duration="200" />
<item android:drawable="#drawable/loadbar_03" android:duration="200"/>
</animation-list>
Also, you are setting the image in your xml layout, but animated the background, so you need to either change the xml layout to this:
<ImageView android:id="#+id/loaddialog_animation" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/loadanimation"
android:layout_marginRight="10dp" />
or change you code to get the src file rather than the background, like this:
image = (ImageView) findViewById(R.id.loaddialog_animation);
image.set(R.drawable.loadanimation);
animation = (AnimationDrawable) image.getDrawable();
Faced the same issue today. Placing the animation.start() in the onShow() method of OnShowListener did the trick for me.
public class CustomProgressDialog extends Dialog
{
ImageView progressImage;
AnimationDrawable frameAnimation;
public CustomProgressDialog(Context context)
{
super(context);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.custom_progress);
getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
progressImage = (ImageView) findViewById(R.id.custom_progress_image);
progressImage.setBackgroundResource(R.anim.progress_anim);
frameAnimation = (AnimationDrawable) progressImage.getBackground();
OnShowListener osl = new OnShowListener()
{
#Override
public void onShow(DialogInterface dialog)
{
frameAnimation.start();
}
};
setOnShowListener(osl);
OnDismissListener odl = new OnDismissListener()
{
#Override
public void onDismiss(DialogInterface dialog)
{
frameAnimation.stop();
}
};
setOnDismissListener(odl);
}
}
I'm not sure this is even possible. I have this button:
<Button
android:id="#+id/b1"
android:layout_width="wrap_content"
android:layout_height="45px"
android:drawableTop="#drawable/buttontv"
android:layout_weight="1"
android:background="#null"
android:textColor="#ffffff"
android:textSize="9px"
android:text="TV"/>
And this button has this item 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/tv" />
<item
android:state_focused="true"
android:state_pressed="true"
android:drawable="#drawable/tv_pressed" />
<item
android:state_focused="false"
android:state_pressed="true"
android:drawable="#drawable/tv_pressed" />
<item
android:drawable="#drawable/tv" />
</selector>
And in my application I use this code for when clicking my button:
OnClickListener b1Listener = new OnClickListener(){
#Override
public void onClick(View v) { loadUrl("http://example.org/"); v.setPressed(true); }
};
Button b1 = (Button) findViewById(R.id.b1);
b1.setOnClickListener(b1Listener);
What I would like that when I have pressed the button, the drawableTop sets to one of the items with the #drawable/tv_pressed attribute value - and stays there (as in 'this is the currently active button').
I tried adding v.setPressed(true) in the onClick function (as this was all I could find with Google) but that didn't work.
Can this be done? Or is there a better alternative to what I'm trying to accomplish?
If you need a button that gets pressed and stays active, use a ToggleButton
https://stackoverflow.com/a/9750125/1257369
button.setFocusable(true);
button.setFocusableInTouchMode(true);///add this line
or with styles.xml
<item name="android:focusable">true</item>
<item name="android:focusableInTouchMode">true</item>
as mentioned above by the answer, it is ideal to use a togglebutton but if you are using a listview in this scenario, then the togglebutton will block out your listview's setOnItemClickListener. You can fix that issue as well by adding the descendants as blocked in the listview layout. However some people have reported that even then, their listview items won't click after using toggle buttons.
Are you working with dialogs/dialogfragments?
This code might help you if you are, because i had a simmilar problem and this worked for me. :)
1- extend your class with DialogFragment
,Override Onstart() method.
#Override
public void onStart() {
super.onStart();
final AlertDialog D = (AlertDialog) getDialog();
if (D != null) {
Button positive = (Button) D.getButton(Dialog.BUTTON_POSITIVE);
positive.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
if (edittext.equals("")) {
Toast.makeText(getActivity(), "EditText empty don't close",Toast.LENGTH_SHORT).show();
} else {
D.dismiss(); //dissmiss dialog
}
}
});
}}