I'm creating an application that uses an ImageSwitcher to show some images. I want to show arrows on either side of the screen in addition to a button on the bottom whenever a user has touched the screen or switched images. Just like you'll see when viewing screenshots for an application in Android Market.
So far I've had my activity implement OnGestureListener, and I've created an AsyncTask that fades in, sleeps for 1 seconds then fades out again whenever the ACTION_UP event is triggered. The problem is that I want to remove an arrow if the user flings to another image. There's three images.
Here's an exerpt of my code.
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
new FadeInOutButtons().execute();
}
return mGesture.onTouchEvent(event);
}
private void fadeOutAll() {
Animation fadeOut = AnimationUtils.loadAnimation(
MyActivity.this, android.R.anim.fade_out);
mButtonHolder.startAnimation(fadeOut);
mButtonHolder.setVisibility(View.GONE);
if (mRightArrow.getVisibility() == View.VISIBLE) {
mRightArrow.startAnimation(fadeOut);
mRightArrow.setVisibility(View.GONE);
}
if (mLeftArrow.getVisibility() == View.VISIBLE) {
mLeftArrow.startAnimation(fadeOut);
mLeftArrow.setVisibility(View.GONE);
}
}
private class FadeInOutButtons extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
return null;
}
#Override
protected void onPostExecute(Void result) {
fadeOutAll();
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
Animation fadeIn = AnimationUtils.loadAnimation(
MyActivity.this, android.R.anim.fade_in);
mButtonHolder.startAnimation(fadeIn);
mButtonHolder.setVisibility(View.VISIBLE);
final int sz = mImages.size();
if (sz > 1) {
if (mPosition < sz - 1) {
mRightArrow.startAnimation(fadeIn);
mRightArrow.setVisibility(View.VISIBLE);
}
if (mPosition > 0) {
mLeftArrow.startAnimation(fadeIn);
mLeftArrow.setVisibility(View.VISIBLE);
}
}
super.onPreExecute();
}
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
final int sz = mImages.size();
if (sz > 1) {
if (velocityX < 0 && mPosition < sz - 1) {
mInactive = mActive;
mActive = (ImageView) mSwitcher.getNextView();
mActive.setImageResource(mImages.get(++mPosition));
mSwitcher.showNext();
} else if (velocityX > 0 && mPosition > 0) {
mInactive = mActive;
mActive = (ImageView) mSwitcher.getNextView();
mActive.setImageResource(mImages.get(--mPosition));
mSwitcher.showPrevious();
}
}
mInactive.setImageURI(null);
return true;
}
Have any of you done anything like this before? How can I make only the left arrow disappear when the third image is focused, and only the right one when the first is... And so on... ? I've been stuck on this for an hour.
Thanks!
Sorry about the formatting.
Firstly, don't use an AsyncTask if you're not actually doing any background work (sleeping doesn't count as work!). Use a Handler attached to the UI thread and postDelayed() to it.
WORKING EXAMPLE OF FADING VIEWS IN AND OUT
Firstly, your layout main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageSwitcher
android:id="#+id/imageSwitcher"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
<Button android:id="#+id/prev"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:text="Previous"
/>
<Button android:id="#+id/next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:text="Next"
/>
</RelativeLayout>
Yes I'm using buttons rather than imageviews, just to keep the example simple.
Now the fade in and fade out animations:
fade_in.xml:
fade_out.xml:
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/accelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="500"
android:fillAfter="true"/>
Finally, some actual code for your main activity:
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.ImageSwitcher;
import android.widget.ImageView;
import android.widget.ViewSwitcher.ViewFactory;
public class MainActivity extends Activity implements ViewFactory, OnTouchListener {
ImageSwitcher imageSwitcher;
View prev,next;
Handler handler = new Handler();
static final int[] images = {
R.drawable.pic1,
R.drawable.pic2,
R.drawable.pic3
};
int currentImageIndex = 0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imageSwitcher = (ImageSwitcher)findViewById(R.id.imageSwitcher);
imageSwitcher.setFactory(this);
imageSwitcher.setOnTouchListener(this);
prev = findViewById(R.id.prev);
next = findViewById(R.id.next);
setCurrentImage();
scheduleHideButtons();
}
private void setCurrentImage() {
imageSwitcher.setImageResource(images[currentImageIndex]);
}
private void scheduleHideButtons() {
handler.removeCallbacks(hideButtonsRunnable);
handler.postDelayed(hideButtonsRunnable, 3000);
}
private Runnable hideButtonsRunnable = new Runnable() {
#Override public void run() {
fadeButtons(false);
}
};
private void fadeButtons(final boolean fadeIn) {
if (fadeIn) {
scheduleHideButtons();
}
Animation anim = AnimationUtils.loadAnimation(this, fadeIn?R.anim.fade_in:R.anim.fade_out);
prev.startAnimation(anim);
next.startAnimation(anim);
anim.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
prev.setVisibility(fadeIn?View.VISIBLE:View.GONE);
next.setVisibility(fadeIn?View.VISIBLE:View.GONE);
}
#Override public void onAnimationRepeat(Animation animation) { }
#Override public void onAnimationStart(Animation animation) { }
});
}
#Override
public View makeView() {
ImageView imageView = new ImageView(this);
imageView.setBackgroundColor(0xFF000000);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setLayoutParams(new ImageSwitcher.LayoutParams(
ImageSwitcher.LayoutParams.FILL_PARENT,
ImageSwitcher.LayoutParams.FILL_PARENT));
return imageView;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction()==MotionEvent.ACTION_DOWN) {
if (prev.getVisibility()==View.GONE) {
fadeButtons(true);
}
else {
scheduleHideButtons();
}
}
return false;
}
}
Related
I added Images view dynamically to my Linear layout,
I want to achieve
Here is sample code what I have done
MainActivity
package ksp.com.animationssample;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity {
private Button btn_expand;
private Button btn_collapse;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_expand = (Button) findViewById(R.id.btn_expand);
btn_collapse = (Button) findViewById(R.id.btn_collapse);
LinearLayout.LayoutParams vp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
final LinearLayout layout = (LinearLayout) findViewById(R.id.imageLayout);
for (int i = 0; i < 3; i++) {
final ImageView image = new ImageView(MainActivity.this);
image.setLayoutParams(vp);
if (i == 0)
image.setImageDrawable(getResources().getDrawable(R.drawable.item_image1));
else image.setImageDrawable(getResources().getDrawable(R.drawable.item_image2));
if (i == 2)
image.setVisibility(View.VISIBLE);
else
image.setVisibility(View.GONE);
layout.addView(image);
}
btn_expand.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
expandOrCollapse(layout.getChildAt(2), true, layout.getChildAt(0).getHeight() + layout.getChildAt(1).getHeight());
expandOrCollapse(layout.getChildAt(1), true, layout.getChildAt(0).getHeight());
expandOrCollapse(layout.getChildAt(0), true, 0);
}
});
btn_collapse.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
expandOrCollapse(layout.getChildAt(0), false, 0);
expandOrCollapse(layout.getChildAt(1), false, layout.getChildAt(0).getHeight());
expandOrCollapse(layout.getChildAt(2), false, layout.getChildAt(0).getHeight() + layout.getChildAt(1).getHeight());
}
});
}
public void expandOrCollapse(final View v, boolean is_expand, final int animheight) {
TranslateAnimation anim = null;
if (is_expand) {
anim = new TranslateAnimation(0.0f, 0.0f, -animheight, 0.0f);
v.setVisibility(View.VISIBLE);
Animation.AnimationListener expandedlistener = new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
};
anim.setAnimationListener(expandedlistener);
} else {
anim = new TranslateAnimation(0.0f, 0.0f, 0.0f, -animheight);
Animation.AnimationListener collapselistener = new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
v.setVisibility(View.GONE);
}
};
anim.setAnimationListener(collapselistener);
}
anim.setDuration(1500);
anim.setInterpolator(new AccelerateInterpolator(0.5f));
v.startAnimation(anim);
}
}
activity_mainn.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:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:orientation="vertical"
android:background="#android:color/holo_blue_dark"
tools:context="ksp.com.animationssample.MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:id="#+id/btn_expand"
android:text="Expand"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/btn_collapse"
android:text="Collopse"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical">
<LinearLayout
android:layout_width="match_parent"
android:id="#+id/imageLayout"
android:gravity="center"
android:orientation="vertical"
android:layout_height="wrap_content">
</LinearLayout>
<!--android:animateLayoutChanges="true"-->
</ScrollView>
</RelativeLayout>
when I click expand button at the first time is not showing the animation from the second time it's working.
enable Visible the item after click on collapse button.
What to do next :
When I selected any View item it has to show select animation then collapse animation, after collapse it has to appear as top View like I mention in Image above. Currently I am hard code the count of the views and wrote static animations for each view with static heights of animations i.e (expandOrCollapse(view, height_of_view))
I search a while for this, but no luck.
I follow the Vie expand/collapse and smooth expand / collapse but they can't help me expand all views in Linear layout.
Can we do this List views are recycler view or something ?
for time saving I have added my sample to git hub you can try it Animation Sample Github
Suggest me, please.
I have made separate class for it. Check if it works for you:
public class DropDownAnim extends Animation {
private final int sourceHeight;
private final int targetHeight;
private final View view;
private final boolean down;
public DropDownAnim(View view, int sourceHeight, int targetHeight, boolean down) {
this.view = view;
this.sourceHeight = sourceHeight;
this.targetHeight = targetHeight;
this.down = down;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int newHeight;
if (down) {
newHeight = sourceHeight + (int) (targetHeight * interpolatedTime);
} else {
newHeight = sourceHeight + targetHeight - (int) (targetHeight * interpolatedTime);//(int) (targetHeight * (1 - interpolatedTime));
}
view.getLayoutParams().height = newHeight;
view.requestLayout();
view.setVisibility(down ? View.VISIBLE : View.GONE);
}
#Override
public void initialize(int width, int height, int parentWidth,
int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
#Override
public boolean willChangeBounds() {
return true;
}
}
While working with this. For expand
public void expand(final View v) {
final int sourceHeight = v.getLayoutParams().height;
final int targetHeight = getResources().getDimensionPixelSize(R.dimen.notification_height);//v.getMeasuredHeight();
DropDownAnim a = new DropDownAnim(v,targetHeight,true);
a.setDuration((int) (targetHeight / v.getContext().getResources().getDisplayMetrics().density));
a.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
// Your code on end of animation
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
v.setVisibility(View.INVISIBLE);
v.startAnimation(a);
}
For collapse:
public void collapse(final View v) {
final int sourceHeight = v.getLayoutParams().height;
final int targetHeight = v.getMeasuredHeight();
DropDownAnim a = new DropDownAnim(v, targetHeight, false);
a.setDuration((int) (targetHeight / v.getContext().getResources().getDisplayMetrics().density));
a.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
// Your code on end of animation
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
v.startAnimation(a);
}
Update:
sourceHeight added to prevent view blinking.
Try to not hide your target view (now you set visibility GONE for all views after collapsed animation end) and do this:
targetView.bringToFront();
targetView.invalidate();
targetView.getParent().requestLayout();
I got swipe up and swipe down for a layout by using setOnTouchListener (For understanding see below images)
Images
But i want to swipe up and swipe down the layout when clicking on the button not when OnTouchListener. For this i tried almost all examples in the online but i didn't get any solution according to my requirement. So, please help me to make OnTouchListener event when clicking on the button
My Code
Activity
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.RelativeLayout;
public class SwipeUpActivity extends Activity {
RelativeLayout rlSwipeHolder, rlSwipe1, rlSwipe2;
private float startY;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_swipe_up);
rlSwipeHolder = (RelativeLayout) findViewById(R.id.rl_swipe_up_holder);
rlSwipe1 = (RelativeLayout) findViewById(R.id.rl_swipe_up_1);
rlSwipe2 = (RelativeLayout) findViewById(R.id.rl_swipe_up_2);
rlSwipe2.setVisibility(View.GONE);
rlSwipeHolder.setOnTouchListener(new OnTouchListener() {
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startY = event.getY();
break;
case MotionEvent.ACTION_UP: {
float endY = event.getY();
if (endY < startY) {
System.out.println("Move UP");
rlSwipeHolder.setVisibility(View.VISIBLE);
rlSwipe1.setVisibility(View.VISIBLE);
rlSwipe2.setVisibility(View.VISIBLE);
} else {
rlSwipeHolder.setVisibility(View.VISIBLE);
rlSwipe1.setVisibility(View.VISIBLE);
rlSwipe2.setVisibility(View.GONE);
}
}
}
return true;
}
});
}
}
Layout
<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:background="#FFFFFF"
tools:context="com.app.swipeup.SwipeUpActivity" >
<RelativeLayout
android:id="#+id/rl_swipe_up_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#0000FF"
android:padding="5dp" >
<RelativeLayout
android:id="#+id/rl_swipe_up_1"
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="#585858" >
</RelativeLayout>
<RelativeLayout
android:id="#+id/rl_swipe_up_2"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_below="#+id/rl_swipe_up_1"
android:background="#FE2E2E" >
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
Edit
Like this video i have to open the layout and close the layout (or swipe up the layout and swipe down the layout) when clicking the button
Create object of your onTouchListenr.
OnTouchListener ot = new OnTouchListener(){-------- YOUR CODE ---}
on enable button click
rlSwipeHolder.setOnTouchListener(ot);
on disable button clik
rlSwipeHolder.setOnTouchListener(null);
This is not the exact solution for this, but i'm posting here, because it may help others.
Answer
I saw lot of solutions for setOnTouchListener after setOnClickListener but i didn't get. So, i followed the animation for layout up and down as discussed in this link
and i did minute changes to the code as
Activity
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.RelativeLayout;
public class SwipeUpActivity extends Activity {
RelativeLayout mRelativeLayout;
RelativeLayout mRelativeLayoutHeader;
ValueAnimator mAnimator;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_swipe_up);
mRelativeLayout = (RelativeLayout) findViewById(R.id.expandable);
// mLinearLayout.setVisibility(View.GONE);
mRelativeLayoutHeader = (RelativeLayout) findViewById(R.id.header);
// Add onPreDrawListener
mRelativeLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
mRelativeLayout.getViewTreeObserver().removeOnPreDrawListener(this);
mRelativeLayout.setVisibility(View.GONE);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
mRelativeLayout.measure(widthSpec, heightSpec);
mAnimator = slideAnimator(0, mRelativeLayout.getMeasuredHeight());
return true;
}
});
mRelativeLayoutHeader.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mRelativeLayout.getVisibility() == View.GONE) {
expand();
} else {
collapse();
}
}
});
}
private void expand() {
// set Visible
mRelativeLayout.setVisibility(View.VISIBLE);
mAnimator.start();
}
private void collapse() {
int finalHeight = mRelativeLayout.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animator) {
// Height=0, but it set visibility to GONE
mRelativeLayout.setVisibility(View.GONE);
}
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
mAnimator.start();
}
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// Update Height
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = mRelativeLayout.getLayoutParams();
layoutParams.height = value;
mRelativeLayout.setLayoutParams(layoutParams);
}
});
return animator;
}
}
Layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<RelativeLayout
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="64dp"
android:background="#FCF">
</RelativeLayout>
<RelativeLayout
android:id="#+id/expandable"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_below="#+id/header"
android:background="#FFF">
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
In trying to add animation to ImageViews, I don't seem to get the multithreading right which is giving me incorrect results.
This is the part where I am calling the animation >>
startAnimation(gameController.getSecondImage()); // 1
...
startAnimation(gameController.getFirstImage()); // 2
...
startAnimation(gameController.getSecondImage()); // 3
...
The problem here is that when I was not creating a separate thread, for the startAnimation() function, all 3 calls happened simultaneously and everything got messed up. But still now it is not working perfectly and the 1st & 3rd calls are jumbled up.
public void startAnimation(final ImageView image1) {
final ImageView image2 = cardViewMap.get(cardSwapMap.get(image1.getId()));
Runnable animate = new Runnable() {
#Override
public void run() {
animationController.animate(image1, image2);
}
};
Thread animationThread = new Thread(animate);
animationThread.start();
try { //
animationThread.join(); //
} catch (InterruptedException e) { // Added Later
Log.d("ERROR", e.toString()); //
} //
}
I tried to experiment with join() but it didn't work out, it is giving more radical outcomes now. I thought that using join() will ensure excution of the previous calls to startAnimation() before starting a new.
EDIT: I have tracked the issue and the issue is that my startAnimation() function is being called when the main Looper is running. So it is being executed after all three calls to the function has been made. I need to ensure that startAnimation() runs at the time when I make the call, and is executed before the next call to the same function happens. Any ideas how to ensure this?
try to run this code it will help you understand a work around, once you run it it will be easier for you to understand,
make an layout name it animation_test_activity.xml code is below
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:src="#drawable/ic_launcher"
android:visibility="invisible" />
<ImageView
android:id="#+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/imageView3"
android:layout_alignParentTop="true"
android:src="#drawable/ic_launcher"
android:visibility="invisible" />
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/imageView3"
android:layout_alignParentTop="true"
android:src="#drawable/ic_launcher"
android:visibility="invisible" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/imageView3"
android:layout_alignParentBottom="true"
android:text="click me" />
</RelativeLayout>
now in make an activity named AnimationTest.java the code is as mentioned below.
package com.some.servewrtest;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AnimationSet;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.ImageView;
public class AnimationTest extends Activity implements OnClickListener {
private ImageView[] imageViews = new ImageView[3];
private Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.animation_test_activity);
initializeUI();
}
private void initializeUI() {
// TODO Auto-generated method stub
imageViews[0] = (ImageView) findViewById(R.id.imageView1);
imageViews[1] = (ImageView) findViewById(R.id.imageView2);
imageViews[2] = (ImageView) findViewById(R.id.imageView3);
button = (Button)findViewById(R.id.button1);
button.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
AnimationSet set = new AnimationSet(true);
TranslateAnimation[] animations = new TranslateAnimation[3];
int duration = 300;
animations[0] = createCoins(0, duration*1, 0, 0, 0, 270);
animations[1] = createCoins(1, duration*2, 0, -100, 0, 270);
animations[2] = createCoins(2, duration*3, 0, 100, 0, 270);
set.addAnimation(animations[0]);
set.addAnimation(animations[1]);
set.addAnimation(animations[2]);
set.start();
}
private TranslateAnimation createCoins(int i, int duration, int fromXDelta, int toXDelta, int fromYDelta, int toYDelta) {
// TODO Auto-generated method stub
TranslateAnimation animation = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);
animation.setDuration(duration+1900);
animation.setFillAfter(false);
imageViews[i].setVisibility(ImageView.VISIBLE);
imageViews[i].setAnimation(animation);
imageViews[i].setVisibility(ImageView.INVISIBLE);
return animation;
}
}
This code is working you can test it as well that you may customize the way you want to use it.
Now we have a working example we will see how did we get there,
First if you try to animate same image over and over using AnimationSet or making different TranslateAnimation reference type to same image that doesn't work because a single image tries to be at two different places virtually at the same time. So what happens is only first animation is seen and others are ignored by android it is one of the result of repeat method doesn't work in android.
To solve this what we can do is have as many Views as we need to show different animation on each one a separate View this time. It works as each animation is related to single view and they can work concurrently.
I am in no position to tell not not to go for Multi-Threading but remember you are trying to do this on UI Thread so if you have many animations in your app it will bog your app with these threads that is quite possible.
if you want to listen to an event when a particular animation is over lets say animation then do this
animation..setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
Log.d(TAG, "Animation has started");
}
#Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
Log.d(TAG, "Animation is repeat");
}
#Override
public void onAnimationEnd(Animation animation) {
// TODO Auto-generated method stub
Log.d(TAG, "Animation is over");
}
});
by doing this you can start a new animation when previous is over :)
I tried and failed using Android tools. I went back and fixed it with multithreading.
Though there is a lot of other code that I changed, this is one of the important one w.r.t. my issue-
package thakur.rahul.colourmemory.controller;
import thakur.rahul.colourmemory.view.Animation.DisplayNextView;
import thakur.rahul.colourmemory.view.Animation.Flip3dAnimation;
import android.app.Activity;
import android.view.animation.AccelerateInterpolator;
import android.widget.ImageView;
public class AnimationController implements Runnable {
private Activity activity;
private ImageView image1;
private ImageView image2;
private boolean isFirstImage = true;
private volatile static int numThread = 1;
private volatile static int threadAllowedToRun = 1;
private int myThreadID;
private volatile static Object myLock = new Object();
private volatile static boolean hasNotSlept = true;
public volatile static boolean fixForMatch = false;
public AnimationController(Activity activity, ImageView image1, ImageView image2) {
this.activity = activity;
this.image1 = image1;
this.image2 = image2;
this.myThreadID = numThread++;
}
#Override
public void run() {
synchronized (myLock) {
while (myThreadID != threadAllowedToRun)
try {
myLock.wait();
} catch (InterruptedException e) {
} catch (Exception e) {
}
animate();
if (myThreadID % 2 == 0)
if (hasNotSlept || fixForMatch)
try {
Thread.sleep(1000);
hasNotSlept = !hasNotSlept;
} catch (InterruptedException e) {
}
else
hasNotSlept = !hasNotSlept;
myLock.notifyAll();
threadAllowedToRun++;
}
}
public void animate() {
if (isFirstImage) {
applyRotation(0, 90);
isFirstImage = !isFirstImage;
} else {
applyRotation(0, -90);
isFirstImage = !isFirstImage;
}
}
private void applyRotation(float start, float end) {
final float centerX = image1.getWidth() / 2.0f;
final float centerY = image1.getHeight() / 2.0f;
final Flip3dAnimation rotation = new Flip3dAnimation(start, end, centerX, centerY);
rotation.setDuration(300);
rotation.setFillAfter(true);
rotation.setInterpolator(new AccelerateInterpolator());
rotation.setAnimationListener(new DisplayNextView(isFirstImage, image1, image2));
if (isFirstImage)
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
image1.startAnimation(rotation);
}
});
else
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
image2.startAnimation(rotation);
}
});
}
}
This is being called from the main controller as-
public void startAnimation(ImageView image1) {
ImageView image2 = cardViewMap.get(cardSwapMap.get(image1.getId()));
animationController = new AnimationController(activity, image1, image2);
animationThread = new Thread(animationController);
animationThread.start();
}
Basically, every time I need to run the animation, I make and tag the thread so I can run it in order.
Please add your answer if you have a better solution.
I am trying to animate a layout to hide itself (to later animate other layout to take its place also by animation). Must be SDK 8 (android 2.2) compatible.
What I have works great IF the movingLayout's parent (parent_of_moving_layout in my xml) is twice the movingLayout's height, but I want the parent to be the same height so the movingLayout hides itself below so that I can animate another movingLayout2 later to take its place.
I have been working on it for some long hours and I can't find a solution, hoping someone has an idea (tried setFillAfter and setFillEnabled).
Here is my code and xml to reproduce the result:
activity_my.xml
<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"
tools:context=".MyActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MOVE IT"
android:id="#+id/button"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:id="#+id/parent_of_moving_layout">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="50dp"
android:background="#ff93c049"
android:id="#+id/movinglayout"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test Button"
android:id="#+id/testbutton"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
</RelativeLayout>
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="80dp"
android:layout_below="#+id/button"
android:layout_centerHorizontal="true"
android:layout_marginTop="83dp"></FrameLayout>
</RelativeLayout>
MyActivity.java
package coersum.com.testanimation;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.RelativeLayout;
public class MyActivity extends ActionBarActivity {
//Button clicked to make movingLayout move (mButton) and button to make sure the objects moved and not only their displays (testButton)
Button mButton, testButton;
//layout to move and its LayoutParams (relative seems to be the only one that worked on my tests)
RelativeLayout movingLayout;
RelativeLayout.LayoutParams params;
//used to direction of movement for testing
String direction = "down";
//just a counter to see the Log.d changes more clearly
int count = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(mButtonClickListener);
testButton = (Button) findViewById(R.id.testbutton);
testButton.setOnClickListener(testButtonClickListener);
movingLayout = (RelativeLayout) findViewById(R.id.movinglayout);
params = (RelativeLayout.LayoutParams) movingLayout.getLayoutParams();
}
private View.OnClickListener mButtonClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
TranslateAnimation animation;
if (direction.equals("down")) {
animation = new TranslateAnimation(0, 0, 0, 50);
} else {
animation = new TranslateAnimation(0, 0, 0, -50);
}
animation.setFillAfter(true);
animation.setFillEnabled(true);
animation.setDuration(500);
animation.setAnimationListener(mAnimationListener);
movingLayout.startAnimation(animation);
}
};
private View.OnClickListener testButtonClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
count++;
Log.d("Status", "Clicked on Test Button "+count+" "+direction);
}
};
private Animation.AnimationListener mAnimationListener = new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
movingLayout.clearAnimation();
if (direction.equals("down")) {
direction = "up";
params.topMargin = params.topMargin + 50;
} else {
direction = "down";
params.topMargin = params.topMargin - 50;
}
movingLayout.setLayoutParams(params);
}
};
}
After a few more hours of trials, I found an easy and clean solution (it was really just sooo simple, animate down then set View.GONE and to bring it back, set View.VISIBLE before animating up)! Added a scale for DP and finally made the difference between margin and translation.
Here is an updated java file:
package coersum.com.testanimation;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.RelativeLayout;
public class MyActivity extends Activity {
//Button clicked to make movingLayout move (mButton) and button to make sure the objects moved and not only their displays (testButton)
Button mButton, testButton;
//layout to move and its LayoutParams (relative seems to be the only one that worked on my tests)
RelativeLayout movingLayout;
RelativeLayout.LayoutParams params;
//used to direction of movement for testing
String direction = "down";
//just a counter to see the Log.d changes more clearly
int count = 0;
int convertedSize;
float scale;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
scale = getResources().getDisplayMetrics().density;
convertedSize = (int) (50 * scale + 0.5f); // my layout is 50dp in height set it to (minus)-your_size to go up instead of down
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(mButtonClickListener);
testButton = (Button) findViewById(R.id.testbutton);
testButton.setOnClickListener(testButtonClickListener);
movingLayout = (RelativeLayout) findViewById(R.id.movinglayout);
params = (RelativeLayout.LayoutParams) movingLayout.getLayoutParams();
}
private View.OnClickListener mButtonClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
TranslateAnimation animation;
if (direction.equals("down")) {
animation = new TranslateAnimation(0, 0, 0, convertedSize);
} else {
movingLayout.setVisibility(View.VISIBLE); // show the layout before to animate it
animation = new TranslateAnimation(0, 0, convertedSize, 0);
}
animation.setDuration(500);
animation.setAnimationListener(mAnimationListener);
movingLayout.startAnimation(animation);
}
};
private View.OnClickListener testButtonClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
count++; // just for debugging (to make sure the button was gone and not just its display)
Log.d("Status", "Clicked on Test Button " + count + " Dir: " + direction + " Size: " + convertedSize);
}
};
private Animation.AnimationListener mAnimationListener = new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
if (direction.equals("down")) {
movingLayout.setVisibility(View.GONE); // once it translated down, remove it so I'll be free to set other layout to visible to use etc
direction = "up";
} else {
direction = "down";
}
movingLayout.setLayoutParams(params);
movingLayout.clearAnimation();
}
};
public void testClick(View view) {
}
}
The setting of margin is good if you want to just move the layout inside the screen (and actually move the objects and not just their "display" which is what animations do below Honeycomb sdk, but that wasn't my case so this, so far seems to work perfectly.
I currently have implemented an ImageSwitcher in my app, which slides through an array of pictures. Now I want to have a ProgressBar under the picture which shows on which position we are in the collection so the user gets a feeling of how much pictures are left.
Is this possible? Can I have some advices on how I might implement this?
Picture:
progress
[--|--------]
My ImageSwticher:
package com.example.cfaslides;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.ImageSwitcher;
import android.widget.ImageView;
import android.widget.ViewSwitcher.ViewFactory;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ProgressBar;
import android.widget.ViewSwitcher;
import android.widget.Gallery;
import android.widget.Gallery.LayoutParams;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.view.Window;
import android.content.Context;
public class l2_AltInvestActivity extends Activity implements ViewFactory {
ImageSwitcher imageSwitcher;
Integer[] imageList = {
R.drawable.av_01,
R.drawable.av_02,
R.drawable.av_03,
R.drawable.av_04,
R.drawable.av_05
};
int curIndex=0;
int maxIndex = 4; //# imageList -1
int downX, upX;
private Animation mIn1, mOut1, mIn2, mOut2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.slider);
final ProgressBar mProgressBar = (ProgressBar) findViewById(R.id.progressB);
mProgressBar.setProgress(0);
mProgressBar.setMax(maxIndex);
mProgressBar.setVisibility(View.VISIBLE);
mIn1 = AnimationUtils.loadAnimation(l2_AltInvestActivity.this,android.R.anim.slide_in_left);
mOut1 = AnimationUtils.loadAnimation(l2_AltInvestActivity.this,android.R.anim.slide_out_right);
mIn2 = AnimationUtils.loadAnimation(l2_AltInvestActivity.this,R.anim.slide_in_right);
mOut2 = AnimationUtils.loadAnimation(l2_AltInvestActivity.this,R.anim.slide_out_left);
AnimationListener mAnimListener = new AnimationListener() {
public void onAnimationEnd(Animation animation) {
// the in animation has ended so update the ProgressBar with the new
// progress
mProgressBar.setProgress(curIndex); // I don't know your progress?!?
}
#Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
// rest of the callbacks
};
//set this listener for the both of the in animations
mIn1.setAnimationListener(mAnimListener);
mIn2.setAnimationListener(mAnimListener);
// rest of the onCreate method
imageSwitcher = (ImageSwitcher) findViewById(R.id.switcher);
imageSwitcher.setFactory(this);
imageSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,android.R.anim.fade_in));
imageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,android.R.anim.fade_out));
imageSwitcher.setImageResource(imageList[curIndex]);
imageSwitcher.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
downX = (int) event.getX();
Log.i("event.getX()", " downX " + downX);
return true;
}
else if (event.getAction() == MotionEvent.ACTION_UP) {
upX = (int) event.getX();
Log.i("event.getX()", " upX " + downX);
if (upX - downX > 100) {
imageSwitcher.setInAnimation(AnimationUtils.loadAnimation(l2_AltInvestActivity.this,android.R.anim.slide_in_left));
imageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(l2_AltInvestActivity.this,android.R.anim.slide_out_right));
//curIndex current image index in array viewed by user
curIndex--;
if (curIndex < 0) {
curIndex = maxIndex; //maximum
}
//imageList :-image list array
imageSwitcher.setImageResource(imageList[curIndex]);
//GalleryActivity.this.setTitle(curIndex);
}
else if (downX -upX > -100) {
curIndex++;
if (curIndex > maxIndex) {
curIndex = 0;
}
imageSwitcher.setInAnimation(AnimationUtils.loadAnimation(l2_AltInvestActivity.this,R.anim.slide_in_right));
imageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(l2_AltInvestActivity.this,R.anim.slide_out_left));
imageSwitcher.setImageResource(imageList[curIndex]);
//GalleryActivity.this.setTitle(curIndex);
}
return true;
}
return false;
}
});
} //END onCreate
#Override
public View makeView() {
ImageView i = new ImageView(this);
i.setScaleType(ImageView.ScaleType.FIT_CENTER);
i.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
i.setBackgroundColor(0xFF000000);
return i;
} //END makeView
} // END Class
Slider:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="#+id/widget32"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<ProgressBar
android:id="#+id/progressB"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageSwitcher android:id="#+id/switcher"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
>
</ImageSwitcher>
</RelativeLayout>
now i like to have an progress bar under the picture which shows on
which position we are in the collection. so that someone gets a
feeling how much pictures are left.
Place a ProgressBar in your R.layout.slider layout file
Make the four different Animations that you used for the ImageSwitcher's transitions as fields in your Activity and also set an AnimationListener for each of them:
//...
private Animation mIn1, mOut1, mIn2, mOut2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.slider);
final ProgressBar = (ProgressBar) findViewById(R.id.theIdOfTheProgressBar);
mIn1 = AnimationUtils.loadAnimation(l2_AltInvestActivity.this,android.R.anim.slide_in_left);
mOut1 = AnimationUtils.loadAnimation(l2_AltInvestActivity.this,android.R.anim.slide_out_right);
mIn2 = AnimationUtils.loadAnimation(l2_AltInvestActivity.this,R.anim.slide_in_right);
mOut2 = AnimationUtils.loadAnimation(l2_AltInvestActivity.this,R.anim.slide_out_left);
AnimationListener mAnimListener = new AnimationListener() {
public void onAnimationEnd(Animation animation) {
// the in animation has ended so update the ProgressBar with the new
// progress
mProgressBar.setProgress(curIndex); // I don't know your progress?!?
}
// rest of the callbacks
});
//set this listener for the both of the in animations
mIn1.setAnimationListener(mAnimListener);
mIn2.setAnimationListener(mAnimListener);
// rest of the onCreate method
In the onTouch method update the ImageSwitcher with the proper animations(from mIn1, mOut1, mIn2, mOut2)