I am doing a project using TranslateAnimation in Android. In that I am translating images successfully but I have to add onClickListener to the images. That means I have click the images during translating and get their values but I am getting the onClick action on the images.
I am using following code:
public class SampleGame extends Activity implements OnClickListener {
int x10, x20, y10, y20;
ImageView img;
Button animation;
Handler transHandler;
RelativeLayout layout;
Random rand;
int mSpeedX, mSpeedY;
int width, height;
Thread thread;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
layout = (RelativeLayout) findViewById(R.id.layout);
animation = (Button) findViewById(R.id.animation);
animation.setOnClickListener(this);
rand = new Random();
width = getWindow().getWindowManager().getDefaultDisplay().getWidth() - 20;
height = getWindow().getWindowManager().getDefaultDisplay().getHeight() - 70;
x10 = width - rand.nextInt(width);
y10 = height;
x20 = width;
y20 = height - rand.nextInt(height);
thread = new Thread();
img.setOnClickListener(this);
}
public void onPause() {
super.onPause();
thread = null;
}
#Override
public void onClick(View v) {
if (v.equals(img)) {
Log.e("img clicked :", "yaaaaaaaaa");
}
if (v.equals(animation)) {
animation.setVisibility(View.INVISIBLE);
callTransform();
}
}
public void callTransform() {
if (thread != null) {
thread = new Thread() {
public void run() {
// Log.e("X1 value :",String.valueOf(x10));
// Log.e("X2 value :",String.valueOf(x20));
// Log.e("Y1 value :",String.valueOf(y10));
// Log.e("Y2 value :",String.valueOf(y20));
transformAnimation(x10, x20, y10, y20, img, 4000);
try {
Thread.sleep(4000);
} catch (Exception e) {
}
// Message msg=transHandler.obtainMessage();
// transHandler.sendMessage(msg);
x10 = x20;
y10 = y20;
if (x10 == width) {
x20 = width - rand.nextInt(width);
y20 = 0;
} else if (y10 == 0) {
x20 = 0;
y20 = height - rand.nextInt(height);
} else if (x10 == 0) {
x20 = width - rand.nextInt(width);
y20 = height;
} else if (y10 == height) {
x20 = width;
y20 = height - rand.nextInt(height);
}
callTransform();
}
};
thread.start();
}
}
public void transformAnimation(int xFrom, int xTo, int yFrom, int yTo, final ImageView image, int time) {
TranslateAnimation anim = new TranslateAnimation(xFrom, xTo, yFrom, yTo);
anim.setDuration(time);
image.setAnimation(anim);
}
}
and I tried the following example also - 2D-Tutorial Example.
But in this also I didn't onClick action for images.
So how to get the onClick action on image during translation?
or
Is there any other way to translate the image with on click action?
Thanks in Advance.
during animation the object remains in its original position but it animates translation so you would need to update the Layout Parameters manually during animation
Related
I created a simple app, just want when I click a button, the imageview will travel to another position.
Below is the code, but it seems that when I click the button, the imageview always begin with the original position, not the real position. Is there any problem with my code?
public class MainActivity extends Activity{
private ImageView iv;
private Button bt;
private AnimatorSet mAniSet;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ddd);
iv = (ImageView) this.findViewById(R.id.imageView1);
bt = (Button) this.findViewById(R.id.button1);
mAniSet = new AnimatorSet();
bt.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
int pointOnScreen[] = new int[2];
iv.getLocationOnScreen(pointOnScreen);
ObjectAnimator AniTranslationX = ObjectAnimator.ofFloat(iv, View.TRANSLATION_X, pointOnScreen[0]+100);
mAniSet.playTogether(AniTranslationX);
mAniSet.setTarget(iv);
mAniSet.setDuration(200).start();
}
});
}
}
If you create a ObjectAnimator.ofFloat(Object, Property, values) and there is only one value, so the origin of the animation will be 0f.
You can find the source into the class android.animation.KeyFrameSet and the following method:
public static KeyframeSet ofFloat(float... values) {
boolean badValue = false;
int numKeyframes = values.length;
FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
if (numKeyframes == 1) {
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
if (Float.isNaN(values[0])) {
badValue = true;
}
} else {
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
for (int i = 1; i < numKeyframes; ++i) {
keyframes[i] =
(FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
if (Float.isNaN(values[i])) {
badValue = true;
}
}
}
if (badValue) {
Log.w("Animator", "Bad value (NaN) in float animator");
}
return new FloatKeyframeSet(keyframes);
}
You can see, with only one value, the start of the animation is 0f (keyframes[0]).
If you put 2 values, your animation will start from the first value and stop at the second:
ObjectAnimator AniTranslationX = ObjectAnimator.ofFloat(iv, View.TRANSLATION_X, pointOnScreen[0], pointOnScreen[0] + 100);
With 3 or more values, the animation will reach all these values over the time of the animation.
I am making horizontal scrollview gallery, and I want to autoscroll it. Now it's scrolling from left to right but when I reach end of list I just simply jump to first one, but it looks really bad, so I want to go scroll around from beginning avoiding just skipping to first one, or if it is not possible just start scrolling to the other side when I reach last view on right (maybe better option). Could someone help me how to do this?
private LinearLayout horizontalOuterLayout;
private HorizontalScrollView horizontalScrollview;
private int scrollMax;
private int scrollPos = 0;
private TimerTask clickSchedule;
private TimerTask scrollerSchedule;
private TimerTask faceAnimationSchedule;
private Timer scrollTimer = null;
private Timer faceTimer = null;
private String[] imageNameArray ={ "sponsors_czarnykot", "sponsors_estradarzeszow","sponsors_klubp","sponsors_kula","sponsors_czarnykot", "sponsors_estradarzeszow","sponsors_klubp","sponsors_kula" };
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.horizontal_layout);
horizontalScrollview = (HorizontalScrollView) findViewById(R.id.horiztonal_scrollview_id);
horizontalOuterLayout = (LinearLayout) findViewById(R.id.horiztonal_outer_layout_id);
horizontalScrollview.setHorizontalScrollBarEnabled(false);
addImagesToView();
ViewTreeObserver vto = horizontalOuterLayout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
horizontalOuterLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
getScrollMaxAmount();
startAutoScrolling();
}
});
}
public void getScrollMaxAmount()
{
int actualWidth = (horizontalOuterLayout.getMeasuredWidth() - 512);
scrollMax = actualWidth;
}
public void startAutoScrolling()
{
if (scrollTimer == null)
{
scrollTimer = new Timer();
final Runnable Timer_Tick = new Runnable()
{
public void run()
{
moveScrollViewRight();
}
};
if (scrollerSchedule != null)
{
scrollerSchedule.cancel();
scrollerSchedule = null;
}
scrollerSchedule = new TimerTask()
{
#Override
public void run()
{
runOnUiThread(Timer_Tick);
}
};
scrollTimer.schedule(scrollerSchedule, 30, 30);
}
}
public void moveScrollViewRight()
{
scrollPos = (int) (horizontalScrollview.getScrollX() + 1.0);
if (scrollPos >= scrollMax)
{
scrollPos = 0;
}
horizontalScrollview.scrollTo(scrollPos, 0);
}
/** Adds the images to view. */
public void addImagesToView()
{
for (int i = 0; i < imageNameArray.length; i++)
{
final ImageView imageView = new ImageView(this);
int imageResourceId = getResources().getIdentifier(imageNameArray[i], "drawable", getPackageName());
Drawable image = this.getResources().getDrawable(imageResourceId);
imageView.setBackgroundDrawable(image);
imageView.setTag(i);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(180, 123);
params.setMargins(0, 25, 0, 25);
imageView.setLayoutParams(params);
horizontalOuterLayout.addView(imageView);
}
}
public void stopAutoScrolling()
{
if (scrollTimer != null)
{
scrollTimer.cancel();
scrollTimer = null;
}
}
public void onBackPressed()
{
super.onBackPressed();
finish();
}
public void onPause()
{
super.onPause();
finish();
}
public void onDestroy()
{
clearTimerTaks(clickSchedule);
clearTimerTaks(scrollerSchedule);
clearTimerTaks(faceAnimationSchedule);
clearTimers(scrollTimer);
clearTimers(faceTimer);
clickSchedule = null;
scrollerSchedule = null;
faceAnimationSchedule = null;
scrollTimer = null;
faceTimer = null;
super.onDestroy();
}
private void clearTimers(Timer timer)
{
if (timer != null)
{
timer.cancel();
timer = null;
}
}
private void clearTimerTaks(TimerTask timerTask)
{
if (timerTask != null)
{
timerTask.cancel();
timerTask = null;
}
}
scrolling back the other way would be easiest.
add in a instance variable that is set to 1.0 (called say scrollDist)
then change this line
scrollPos = (int) (horizontalScrollview.getScrollX() + 1.0);
to
scrollPos = (int) (horizontalScrollview.getScrollX() + scrollDist);
and this line
scrollPos = 0;
to
scrollDist *= -1.0;
this way it will reverse each time it hits the end of the scrollview.
For endless scrolling use the following snnipet
public void getScrollMaxAmount() {
int actualWidth = (horizontalOuterLayout.getMeasuredWidth() - getWindowManager().getDefaultDisplay().getWidth());
scrollMax = actualWidth;
}
public void moveScrollView() {
// ********************* Scrollable Speed ***********************
scrollPos = (int) (horizontalScrollview.getScrollX() + 1.0);
if (scrollPos >= scrollMax) {
Log.v("childCount", ""+scrollMax);
addImagesToView();
getScrollMaxAmount();
}
horizontalScrollview.scrollTo(scrollPos, 0);
}
I'm using horizontalscrollView to move set of images as a slideshow. I've 5 images in drawable, I'm able to move images from right to left but in some phones it just scrolling to 3rd image and restarting the scroll and in some phones it just stops scrolling till reaching to the end of images in right. Please help !! This is the code I used :
public void getScrollMaxAmount(){
int actualWidth = (horizontalOuterLayout.getMeasuredWidth()-200);
scrollMax = actualWidth;
}
public void startAutoScrolling(){
if (scrollTimer == null) {
scrollTimer=new Timer();
final Runnable Timer_Tick=new Runnable() {
public void run() {
moveScrollView();
}
};
if(scrollerSchedule != null){
scrollerSchedule.cancel();
scrollerSchedule = null;
}
scrollerSchedule = new TimerTask(){
#Override
public void run(){
runOnUiThread(Timer_Tick);
}
};
scrollTimer.schedule(scrollerSchedule, 50, 50);
}
}
public void moveScrollView(){
scrollPos= (int) (hsv2.getScrollX() + 1.0);
if(scrollPos >= scrollMax){
scrollPos=0;
}
hsv2.scrollTo(scrollPos, 0);
}
public void addImagesToView(){
for (int i=0;i<imageNameArray.length;i++){
Log.d("imagname",String.valueOf(imageNameArray.length));
final ImageView imageButton = new ImageView(this);
int imageResourceId = getResources().getIdentifier(imageNameArray[i], "drawable",getPackageName());
Drawable image = this.getResources().getDrawable(imageResourceId);
imageButton.setBackgroundDrawable(image);
imageButton.setTag(i);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(90,LayoutParams.WRAP_CONTENT);
//params.setMargins(0, 25, 0, 25);
imageButton.setLayoutParams(params);
horizontalOuterLayout.addView(imageButton);
}
First calculate width of your scrollview like this here linearlayout is layout inside your scrollview
linearLayout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
LayoutParams layParamsGet = linearLayout.getLayoutParams();
width = layParamsGet.width;
}
});
Then in timertassk just scroll the scrollview upto end
private void callAsynchronousTask() {
final Handler handler = new Handler();
timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
if (x <= width - KeyConstants.SCREEN_WIDTH) {
x = x + 1;
} else {
x = 0;
}
mhorizontalscrollView.scrollTo(x, 0);
} catch (Exception e) {
}
}
});
}
};
timer.schedule(doAsynchronousTask, 0, 5);
}
public class Game_collecting_view extends View
{
Button image_boy;
private static final int BOY_DIAMETER = 200; // initial spot size
int boy_width =0;
int boy_height =0;
public void setGame_collecting(Game_collecting mGame_collecting)
{
this.mGame_collecting = mGame_collecting;
}
// constructs a new View
public Game_collecting_view(Context context, RelativeLayout parentLayout)
{
super(context);
resources = context.getResources(); // save Resources for loading external values
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// get references to various GUI components
relativeLayout = parentLayout;
spotHandler = new Handler(); // used to add spots when game starts
}
#Override
protected void onSizeChanged(int width, int height, int oldw, int oldh)
{
viewWidth = width; // save the new width
viewHeight = height; // save the new height
}
public void set_boy()
{
final Button boy = (Button) layoutInflater.inflate(R.layout.untouched, null);
boy.setX(viewWidth /2);
boy.setY(viewHeight - BOY_DIAMETER);
boy.setPadding(0,0,0,0);
boy.setBackgroundResource(R.drawable.blue);
boy.setLayoutParams(new RelativeLayout.LayoutParams(BOY_DIAMETER, BOY_DIAMETER));
relativeLayout.addView(boy); // add spot to the screen
Toast.makeText(getContext(), "set_boy\nviewWidth=" +viewHeight +"\nviewHeight=" +viewHeight, Toast.LENGTH_SHORT).show();
boy.setOnClickListener
(
new OnClickListener()
{
public void onClick(View v)
{
touchedSpot(boy);
}
}
);
}
public void resume(Context context)
{
resetGame();
}
public void resetGame()
{
for (int i = 1; i <= INITIAL_SPOTS; ++i)
{
spotHandler.postDelayed(addSpotRunnable, i * SPOT_DELAY);
generate_text();
}
set_boy();
}
private Runnable addSpotRunnable = new Runnable()
{
public void run()
{
addNewSpot(); // add a new spot to the game
}
};
Objective:
I would like to set the boy icon at the bottom middle of the screen.
The boy icon is set at this way for later dynamic interface (swipe the screen to the right the boy icon will move to the right, vice versa)
Observation:
The toast reports both the viewWidth and viewHeight =0, and the boy icon appears at 0,0 (left upper corner). If I set the setY(viewHeight + BOY_DIAMETER), the boy icon will be located at (0, 200).
Question:
I would like to ask why the viewWidth and viewHeight both report 0. How could the onSizeChanged be called immediately such that the boy icone could be set at the bottom center of the screen?
Thanks!!
The location is null until Android has calculated their positions. You can retrieve the height and width like this:
image_boy.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int height = image_boy.getHeight();
int width = image_boy.getWidth();
//these values won't be null
}
});
set layout param for setting the view position
I have a list of buttons. When I press a button, a View should slide in a downwards motion out of the button, like this:
Start:
Halfway:
End:
How would I go about this? The View that should slide out is bigger than the button, so first hiding the View behind the button and then sliding it downwards causes the View to be visible above the button. That should not happen.
Any ideas or examples on how to approach this?
I believe the simplest approach is to extend Animation class and override applyTransformation() to change the view's height as follows:
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.LinearLayout;
public class MyCustomAnimation extends Animation {
public final static int COLLAPSE = 1;
public final static int EXPAND = 0;
private View mView;
private int mEndHeight;
private int mType;
private LinearLayout.LayoutParams mLayoutParams;
public MyCustomAnimation(View view, int duration, int type) {
setDuration(duration);
mView = view;
mEndHeight = mView.getHeight();
mLayoutParams = ((LinearLayout.LayoutParams) view.getLayoutParams());
mType = type;
if(mType == EXPAND) {
mLayoutParams.height = 0;
} else {
mLayoutParams.height = LayoutParams.WRAP_CONTENT;
}
view.setVisibility(View.VISIBLE);
}
public int getHeight(){
return mView.getHeight();
}
public void setHeight(int height){
mEndHeight = height;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 1.0f) {
if(mType == EXPAND) {
mLayoutParams.height = (int)(mEndHeight * interpolatedTime);
} else {
mLayoutParams.height = (int) (mEndHeight * (1 - interpolatedTime));
}
mView.requestLayout();
} else {
if(mType == EXPAND) {
mLayoutParams.height = LayoutParams.WRAP_CONTENT;
mView.requestLayout();
}else{
mView.setVisibility(View.GONE);
}
}
}
}
To use it, set your onclick() as follows:
int height;
#Override
public void onClick(View v) {
if(view2.getVisibility() == View.VISIBLE){
MyCustomAnimation a = new MyCustomAnimation(view2, 1000, MyCustomAnimation.COLLAPSE);
height = a.getHeight();
view2.startAnimation(a);
}else{
MyCustomAnimation a = new MyCustomAnimation(view2, 1000, MyCustomAnimation.EXPAND);
a.setHeight(height);
view2.startAnimation(a);
}
}
Regards.
Use something like:
Animation a = new ScaleAnimation(1, 1, 0, 1, Animation.RELATIVE_TO_SELF, (float) 0.5, Animation.RELATIVE_TO_SELF, (float) 0);
a.setFillAfter(true);
view.setAnimation(a);
a.setDuration(1000);
view.startAnimation(a);
Here is simple example of hand-made animation, that provide what you want. It works in test app, but I'm not sure that there is no bugs:
public class MainActivity extends Activity implements OnClickListener {
private Timer timer;
private TimerTask animationTask;
private View view1;
private View view2;
boolean animating;
boolean increasing = true;
int initHeight = -1;
private LayoutParams params;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
timer = new Timer();
view1 = findViewById(R.id.view1);// clickable view
view1.setOnClickListener(this);
view2 = findViewById(R.id.view2);// animated view
params = view2.getLayoutParams();
}
#Override
protected void onDestroy() {
super.onDestroy();
timer.cancel();
}
#Override
public void onClick(View v) {
Toast.makeText(this, "start animating...", Toast.LENGTH_SHORT).show();
animationTask = new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (animationFinished()) {
animating = false;
cancel();//canceling animating task
return;
}
params.height += increasing ? 1 : -1;
view2.setLayoutParams(params);
}
});
}
private boolean animationFinished() {
int viewHeight = view2.getHeight();
if (increasing && viewHeight >= initHeight) {
return true;
}
if (!increasing && viewHeight <= 0) {
return true;
}
return false;
}
};
//if we already animating - we just change direction of animation
increasing = !increasing;
if (!animating) {
animating = true;
int height = view2.getHeight();
params.height = height;
view2.setLayoutParams(params);//change param "height" from "wrap_conent" to real height
if (initHeight < 0) {//height of view - we setup it only once
initHeight = height;
}
timer.schedule(animationTask, 0, 10);//changing repeat time here will fasten or slow down animation
}
}
}
Maybe you can set the height to 0 and gradually increase the height. But then you will have the problem that you have to be sure your text is aligned at the bottom of the view. And also to know what the maximal height of the view should be.
use a sliding list adapter so much easier than messing around with animations
https://github.com/tjerkw/Android-SlideExpandableListView
Simply pass android:animateLayoutChanges to LinearLayout that holds all the views, you will achieve your desired result.
I would do it like that. First the layout for the whole collapsible panel component: (pseudo xml)
RelativeLayout (id=panel, clip)
LinearLayout (id=content, alignParentBottom=true)
LinearLayout (id=handle, above=content)
This should ensure that the content is always below the handle.
Then when you need to collapse:
Animate the top margin of content from 0 to -content.height
Animate the height of the panel from current to current-content.height