How to change width of ImageView in runtime? - java

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.

Related

Animating custom view jumping when being shown

I have a custom view which is a constraint layout and a couple of TextView and EditViews.
On my activity I want to show and hide the custom view based on a Switch being on/off. The same custom view is used on multiple Switches for different parts of capturing some data.
The logic in the switch to make the relevant custom VISIBLE or GONE view works without an issue when I just use the CustomViewName.setVisibility(View.VISIBLE) and CustomViewName.setVisibility(View.GONE) - instead of the ShowOrHideView routine below.
I'm trying to make it look better so instead of the custom view just appearing or disappearing it appears by sliding up/down from the switch (height from 0 to it's expected height), or disappears (expected height to 0).
Replacing the CustomViewName.setVisibility in the switch with a call to the function below to show or hide depending on the Switch being on/off:
Switch On to show the custom view (ignore the hard coded sizes for the example here)
ShowOrHideView(CustomViewName,0,100);
Switch Off to hide the custom view:
ShowOrHideView(CustomViewName,100,0);
private void ShowOrHideView(View parView, int parCurrentHeight,int parNewHeight) {
ValueAnimator mySlideAnimator = ValueAnimator
.ofInt(parCurrentHeight, parNewHeight)
.setDuration(2000); /// 2000 for debug only
mySlideAnimator.addUpdateListener(animation1 -> {
Integer value = (Integer) animation1.getAnimatedValue();
parView.getLayoutParams().height = value.intValue();
parView.requestLayout();
});
mySlideAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(#NonNull Animator parAnimator) {
}
#Override
public void onAnimationEnd(#NonNull Animator parAnimator) {
// If zero at the end of the animation then the view is being hidden
if (parView.getLayoutParams().height == 0) {
parView.setVisibility(View.GONE);
}
}
#Override
public void onAnimationCancel(#NonNull Animator parAnimator) {}
#Override
public void onAnimationRepeat(#NonNull Animator parAnimator) {}
});
if (parCurrentHeight == 0){
parView.setVisibility(View.VISIBLE);
}
AnimatorSet myAnimationSet = new AnimatorSet();
myAnimationSet.setInterpolator(new AccelerateDecelerateInterpolator());
myAnimationSet.play(mySlideAnimator);
myAnimationSet.setStartDelay(1000); // Delayed start for debug only
myAnimationSet.start();
}
The hiding of the custom view works OK with it correctly being set to GONE so the space is no longer there.
But when showing the custom view, the height correctly gets set in the animation, but there's an initial "blip" where the whole custom view gets shown before it then appears as height with 0 up to height of 100.
Any ideas how to make the custom view appear with the height getting larger (to make it appear nicely) and avoid the "blip" where it briefly shows the whole view before the animation? In my example I've temporarily put the setStartDelay(1000) to prove to myself the custom view appears fully when view becomes VISIBLE, then when the animation starts the custom view appears as if the height is 0 to 100
Thanks

How to set ImageView permanently at a position after TranslateAnimation

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.

Resizing Views before drawing

In my layout I have a GridView containing 4 custom ImageViews. I'm setting GridView's visibility to invisible until all ImageViews are resized at first but when the GridView is shown, there's a short blink with ImageViews still unchanged.
blink for a split second
views are resized in a moment
Each ImageView creates separate listener in order to scale its size:
//Setting new params as half of parent's size and increasing counter
if (getViewTreeObserver().isAlive()) {
final ViewTreeObserver viewTreeObserver = getViewTreeObserver();
viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
getViewTreeObserver().removeOnPreDrawListener(this);
View parent = (View) getParent();
int dimension = Math.min(parent.getWidth(), parent.getHeight()) / 2;
mThisImageView.setLayoutParams(new AbsListView.LayoutParams(dimension, dimension));
ResizeCounter.setCounter(ResizeCounter.getCounter() + 1);
return true;
}
});
}
//Activity listens to the moment when all ImageViews have been resized
ResizeCounter.addCounterListener(new OnResizeCounterChangeListener() {
#Override
public void onResizeCounterChanged() {
if (ResizeCounter.getCounter() == 4) {
mAnswerGridView.setVisibility(View.VISIBLE);
}
}
});
I've also tried to resize them in onGlobalLayout method (same result) and to override onMeasure method (parent View is still null at this point).
I suspect that it's too late to change views in onPreDraw() but is there a method that can be called earlier inside which I can be sure that all views have been measured?
Try to call mAnswerGridView.requestLayout() before mAnswerGridView.setVisibility(View.VISIBLE);
This may not work because as it's stated at Android Developers
This will schedule a layout pass of the view tree.
So you may better force relayout:
relayoutChildren(View view) {
view.measure(
View.MeasureSpec.makeMeasureSpec(view.getMeasuredWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(view.getMeasuredHeight(), View.MeasureSpec.EXACTLY));
view.layout(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()); }
I've created a handler that schedules setting visibility right after calling requestLayout.
Works well in this case.
ResizeCounter.addCounterListener(new OnResizeCounterChangeListener() {
#Override
public void onResizeCounterChanged() {
if (ResizeCounter.getCounter() == 4) {
mAnswerGridView.requestLayout();
Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
mAnswerGridView.setVisibility(View.VISIBLE);
}
});
}
}
});

Android TextView: onClick after Moving TextView

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);

When in the Activity life cycle are UI elements available to be measured?

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.

Categories

Resources