I'm trying to get my textView to react to a user's tap.
I found out that I actually have to set android:clickable="true", so my function is actually called now.
But my problem is, that I'm using an animation to move my textView within my activity (from bottom to top). So now the onClick function is only called when you tap where my textView used to be, not where it actually is.
How do you fix this?
EDIT:
Unfortunately, I wasn't able to move the actual TextView programmatically (I'm using a RelativeLayout) like the first answer suggests.
However, I could overlay the position of my TextView with another TextView (transparent) that's clickable only when the animation comes to an end.
Works perfectly.
When you are doing animations the TextView is only visualy moved (the graphic rendering representation is only moved on the screen) but the real TextView object stays on the old position. You have to manually (programatically) move the TextView to the new position.
Take a look at this presentation from Romain Guy and Chet Haase.
Chet Haase is taking about this issue at the 42:00 min. Take a look at the whole presentation if you have time. They are talking about some really usefull things.
I recently had to do this. You didn't provide any code, so this will have to do. The key is setting bottomMargins to compensate.
Animation yourAnimation = AnimationUtils.loadAnimation(getActivity().getApplicationContext(), R.anim.your_anim_file);
slideOutBottom.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
animatedButton.clearAnimation();
Resources r = view.getResources();
int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, -68, r.getDisplayMetrics());
lp = (LinearLayout.LayoutParams) animatedButton.getLayoutParams();
lp.bottomMargin = -50;
cartFunctionButtons.setLayoutParams(lp);
}
});
yourAnimation.setFillAfter(true);
animatedButton.startAnimation(yourAnimation);
Related
I referenced the other questions but couldn't find a solution, also I am fairly new to programming.
So I implemented a TranslateAnimation on my ImageView but once the animation ends it returns to its original position. I used Override onAnimationEnd but that doesn't seem to work. Can someone figure out what should I be doing?
public class PackAnimation extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pack_animation);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
String s = getIntent().getStringExtra("CHOICE");
final ImageView pandya = (ImageView) findViewById(R.id.pandya);
final int amountToMoveRight = 600;
final int amountToMoveDown = 0;
TranslateAnimation anim = new TranslateAnimation(0, amountToMoveRight, 0, amountToMoveDown);
anim.setDuration(100);
anim.setAnimationListener(new TranslateAnimation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) { }
#Override
public void onAnimationRepeat(Animation animation) { }
#Override
public void onAnimationEnd(Animation animation)
{
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)pandya.getLayoutParams();
params.topMargin += amountToMoveDown;
params.leftMargin += amountToMoveRight;
pandya.setLayoutParams(params);
}
});
pandya.startAnimation(anim);
}
}
You can use anim.setFillAfter(true) to the TranslateAnimation and get the button stay at the new position, but the button clicks will not work at the new position.
So use ViewPropertyAnimator or ObjectAnimator. These are property animation and will change the position of the View, whereas the TranslateAnimation is View animation and will not change the actual property of the View.
For example, using ViewPropertyAnimator:
pandya.animate()
.translationX(amountToMoveRight)
.translationY(amountToMoveDown);
Refer the blog for more info:
Finally, the previous animations changed the visual appearance of the
target objects... but they didn't actually change the objects
themselves. You may have run into this problem. Let's say you want to
move a Button from one side of the screen to the other. You can use a
TranslateAnimation to do so, and the button will happily glide along
to the other side of the screen. And when the animation is done, it
will gladly snap back into its original location. So you find the
setFillAfter(true) method on Animation and try it again. This time the
button stays in place at the location to which it was animated. And
you can verify that by clicking on it - Hey! How come the button isn't
clicking? The problem is that the animation changes where the button
is drawn, but not where the button physically exists within the
container. If you want to click on the button, you'll have to click
the location that it used to live in. Or, as a more effective solution
(and one just a tad more useful to your users), you'll have to write
your code to actually change the location of the button in the layout
when the animation finishes.
Use anim.setFillAfter(true); and it will remain on the final position after the end of animation.
want to turn a card in my app. I have 2 ImageViews 1 Cardfront and 2 Cardback.
My theory ->
I change the width of the cardfront from 100% to 0%
I change the width of the cardback from 0% to 100%
I googled for solution on changing the width of am ImageView while runtime, but the solution I found don't work.
// Code for step 1
ViewGroup.LayoutParams params = ivBomb.getLayoutParams();
int width = params.width;
for (int i = 1; i<width; i++) {
params.width--;
ivBomb.setLayoutParams(params);
Thread.sleep(10); // To see the change
}
When I start it without the Thread.sleep(10);, it disappears instantly. But when I start it with the Thread.sleep(10);, it waits ~7s and then disappears instantly.
What am I doing wrong?
You can use animation to get the flip card effect. This card flip animation tutorial here is for a fragment, but you can use the same animations for your views like
Animation cardFlipRightOut = AnimationUtils.loadAnimation(this, R.anim.card_flip_right_out);
cardFlipRightOut.setAnimationListener(new Animation.AnimationListener(){
#Override
public void onAnimationStart(Animation arg0) {
}
#Override
public void onAnimationRepeat(Animation arg0) {
}
#Override
public void onAnimationEnd(Animation arg0) {
Animation cardFlipLeftIn = AnimationUtils.loadAnimation(this, R.anim.card_flip_left_in);
cardFrontView.startAnimation(cardFlipLeftIn);
}
});
cardBackView.startAnimation(cardFlipRightIn);
Try calling one of these after setLayoutParams() :
1. requestLayout()
2. invalidate()
Since, requestLayout() should be called, when view's position or bounds in the parent layout have been changed, while invalidate() should be called when view's appearance has been changed. When you call requestLayout() then onLayout() and onMeasure() methods of the view will be fired, on the other hand when you call invalidate(), then onDraw() method will be fired.
I'm trying to do an animation that goes like this:
The context:
I have two EditText's I need that when you click over one, the another one come out from behind the first one. Here you have some pictures to get a image of what I want.
To do this obviously I need a TranslateAnimation in order to move the second EditText from behind the first one.
My approach:
The first thing that I could thought was in use a FrameLayout put the EditText one over another, and then in the onTouch event of the first one do a TranslateAnimation on the second one. The problem with this is that if I have the FrameLayout height in wrap_content then the animation will be invisible to the user. And if I change on runtime the height of the FrameLayout I will leave a void below the first EditText as you can see in this picture:
The second solution that I thought was add one AnimationListener to the TranslateAnimation and in the onAnimationStart method change the height of the FrameLayout. But the problem with this is that the height of the FrameLayout changes too abruptly. I want keep the animation smooth.
My question:
How can I get a smooth animation of the second EditText from behind the first one, changing the height of the FrameLayout as the second EditText moves down?
Thanks!
Update:
I changed the FrameLayout by a RelativeLayout I searched and there's no difference for this case. I tried scale this RelativeLayout that contains both of the EditText with an AnimationScale in order to display the animation smoothly, but didn't work. Here is my code:
protected void expanse() {
Log.d("Accordion", "expandAccordion");
//Translate the top of the second EditText to its bottom
TranslateAnimation translateSecond = new TranslateAnimation(second.getLeft(), second.getLeft(),
second.getTop(), second.getBottom());
translateSecond.setDuration(1000);
//Scale the relative layout to show the both of them
ScaleAnimation scaleContainer = new ScaleAnimation(container.getLeft(), container.getLeft(),
container.getTop(), second.getBottom());
scaleContainer.setDuration(1000);
//At the end of the scaling, change the height of the relative layout
scaleContainer.setAnimationListener(new AnimationListenerAdapter() {
#Override
public void onAnimationEnd(Animation animation) {
RelativeLayout.LayoutParams params = (LayoutParams) container.getLayoutParams();
params.height = second.getBottom();
container.setLayoutParams(params);
super.onAnimationEnd(animation);
}
});
container.startAnimation(scaleContainer);
second.startAnimation(translateSecond);
}
BTW I can guarantee that if I hardcode some large height like 350dp, the animation is displayed correctly.
UPDATE:
I tried moving both, the second EditText and the layout below. This is the code. BTW for another reasons I changed the ListView by a custom ViewPager, this doesn't change anything.
public class MainActivity extends FragmentActivity {
private EditText first;
private EditText second;
private HoboViewPager pager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pager = (HoboViewPager) findViewById(R.id.pager);
pager.setPageTransformer(true, new RotationPageTransformer());
pager.setAdapter(new SampleAdapter(this, getSupportFragmentManager()));
first = (EditText) findViewById(R.id.location_search_field);
second = (EditText) findViewById(R.id.term_search_field);
first.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
expanseSecondField();
return true;
}
});
}
protected void expanseSecondField() {
TranslateAnimation translateSecondField = new TranslateAnimation(second.getLeft(), second.getLeft(),
second.getTop(), second.getBottom());
translateSecondField.setFillAfter(true);
translateSecondField.setDuration(1000);
TranslateAnimation translateContainer = new TranslateAnimation(pager.getLeft(), pager.getLeft(),
pager.getTop(), pager.getTop() + second.getBottom());
translateContainer.setFillAfter(true);
translateContainer.setDuration(1000);
pager.startAnimation(translateContainer);
second.startAnimation(translateSecondField);
}
}
This didn't work because the TranslateAnimation of the container is executed immediately. The result is the same that when I was trying to change the size of the container at the end of the animation.
How use the 2nd option & try performing two translate animations in tandem: 1 on the EditText, then one on the FrameLayout? Give them both the same exact deltas and duration. This way, the FrameLayout will move down smoothly, then at the end of the animation, change the height of the FrameLayout.
Hope this helps :)
I am defining some animations based on the inflated dimensions of some UI controls. What is the earliest point in the Activity life cycle I can tap into to know when the UI elements have been sized and I can query them for their dimensions?
Right after you set the Content of you Activity via the setContentView() method is the earliest I've been able to grab information from my widgets (size, text and others).
Per Rich's request:
You can determine when the width and height by using the GlobalLayoutListener like so:
final View myView = findViewById(R.id.id_of_view);
ViewTreeObserver vto = myView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int viewHeight = myView.getHeight();
int viewWidth = myView.getWidth();
// Do what you want with the width and height
ViewTreeObserver obs = myView.getViewTreeObserver();
obs.removeGlobalOnLayoutListener(this);
}
});
Full (better) answer: How to retrieve the dimensions of a view?
If you want to drill down to the point that widget have JUST been placed you have to extend each widget you want to monitor.
Then override onDraw method and capture if that view has been drawn one time
private boolean imVisible=false;
public boolean imVisible() {
return imVisible;
}
#Override
protected void onDraw(Canvas canvas) {
if(!imVisible){
imVisible=true;
}
super.onDraw(canvas);
}
Then you can do a for loop to the widgets of interest and you know they are drawn at their position with dimentions.
A far better solution is when the onDraw gets called the first time fire a listener that is drawn. You have to set an array of listeners that watch the progress of the widgets. That way the exact moment that the last widget is on the screen... you know it.
How can I get the alpha/opacity of a View after I've animated it?
My fadeIn() is below - fadeOut() is the same with the endpoints switched.
public void fadeIn(View view) {
Animation animation = new AlphaAnimation(0.0f, 1.0f);
animation.setDuration(1000);
animation.setFillAfter(true);
view.startAnimation(animation);
}
I would highly recommend you to define the animations in an XML-file. The API doesn't have support for getting a specific alpha.
You can still have in mind that the opacity that your view has, is the last one you've defined; in this case, (your fadeIn() method), your latest opacity value is the value you passed into the AlphaAnimation constructor.