I want to make this, but I didn't find any tuts or anything how to make it. (It's called Morph on google website) Can anybody tell me how or send some reference pls?
EDIT:
I want to set the layout from gone to visible... Don't you know when I should do shape.setVisibility(View.VISIBLE)? I tried but animation won't start until second click on button. (On first click layout is just set visible without animation)
Fragment layout:
<EditText
android:id="#+id/editText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:gravity="top"
android:padding="15dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/circle"
android:visibility="gone">
</LinearLayout>
<ImageButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="#color/transparent"
android:contentDescription="share"
android:padding="15dp"
android:src="#drawable/ic_share_55x55px" />
Fragment:
ImageButton fab = (ImageButton) view.findViewById(R.id.share);
fab.setOnClickListener(new View.OnClickListener() {
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
#Override
public void onClick(View view) {
LinearLayout shape = (LinearLayout) getActivity().findViewById(R.id.circle);
// Create a reveal {#link Animator} that starts clipping the view from
// the top left corner until the whole view is covered.
Animator animator = ViewAnimationUtils.createCircularReveal(
shape,
shape.getWidth() - 130,
shape.getHeight()- 130,
0,
(float) Math.hypot(shape.getWidth(), shape.getHeight()));
// Set a natural ease-in/ease-out interpolator.
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(400);
// Finally start the animation
animator.start();
}
});
Your would need to Animate a view (in this example a LinearLayout). Set the x and y values of the createCircularReveal to the fab button.
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
LinearLayout shape = (LinearLayout) rootView.findViewById(R.id.circle);
// Create a reveal {#link Animator} that starts clipping the view from
// the top left corner until the whole view is covered.
Animator animator = ViewAnimationUtils.createCircularReveal(
shape,
0,
0,
0,
(float) Math.hypot(shape.getWidth(), shape.getHeight()));
// Set a natural ease-in/ease-out interpolator.
animator.setInterpolator(new AccelerateDecelerateInterpolator());
// Finally start the animation
animator.start();
}
});
This is the information on the createCircleReveal
createCircularReveal(View view,
int centerX, int centerY, float startRadius, float endRadius);
Example Project:
https://github.com/googlesamples/android-RevealEffectBasic/
UPDATE
Instead of setting the view to GONE, set it to INVISIBLE. Also make the view setEnabled(false) to prevent it from being touched etc.
LinearLayout shape;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.reveal_effect_basic, container, false);
shape = (LinearLayout) view.findViewById(R.id.circle);
shape.setVisibility(View.INVISIBLE);
shape.setEnabled(false);
ImageButton fab = (ImageButton) view.findViewById(R.id.share);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Animator animator = ViewAnimationUtils.createCircularReveal(
shape,
shape.getWidth() - 130,
shape.getHeight() - 130,
0,
(float) Math.hypot(shape.getWidth(), shape.getHeight()));
shape.setVisibility(View.VISIBLE);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
if (shape.getVisibility() == View.VISIBLE) {
animator.setDuration(400);
animator.start();
shape.setEnabled(true);
}
}
});
I am implementing the search functionality which consists of a search box, and a list of categories. For design purposes I have used EditText , GridView etc.
But when the activity starts I don't want all the search box to be displayed. I just want the EditText, and then when the EditText is clicked I need the view to expand, and when some other part of the screen is clicked, for example touching the ListView or pressing the button I need the view to collapse in its default state consisting the EditText.
I can use View.GONE or VIEW.VISIBLE but I want to reach a smooth animation for expanding and collapsing.
My activity_layout.xml:
<RelativeLayout
android:id="#+id/search_box"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:background="#android:color/transparent"
>
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/cv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="#drawable/njoftime_item_background"
card_view:cardCornerRadius="1dp"
card_view:cardElevation="2dp">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:id="#+id/sr"
android:animateLayoutChanges="true"
android:padding="20dp">
<RelativeLayout
android:layout_width="fill_parent"
android:id="#+id/search_area"
android:layout_height="wrap_content"
android:focusableInTouchMode="true"
android:background="#drawable/njoftime_item_background"
>
<ImageButton
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_marginLeft="1dp"
android:id="#+id/btn_search"
android:layout_alignParentRight="true"
android:background="#color/njoftime_main_color"
android:src="#drawable/ic_search_white"
android:onClick="searchPressed"
android:scaleType="fitCenter"
/>
<EditText
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_toLeftOf="#+id/btn_search"
android:id="#+id/search_text"
android:layout_alignParentLeft="true"
android:background="#null"
android:ems="20"
android:textSize="18sp"
android:paddingLeft="10dp"
android:imeOptions="actionSearch"
android:inputType="text"
android:maxLines="1"
android:textColor="#color/njoftime_desc"
android:textCursorDrawable="#null"
/>
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/search_categories_area"
android:layout_below="#+id/search_area"
android:paddingTop="20dp"
android:paddingBottom="10dp"
>
<GridView
android:id="#+id/search_grid"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:drawSelectorOnTop="false"
android:horizontalSpacing="2dp"
android:numColumns="5"
android:padding="4dp"
android:verticalSpacing="4dp" >
</GridView>
</RelativeLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>
For this I have used android:animateLayoutChanges="true" and the following code
my_relative_layout = (RelativeLayout) findViewById(R.id.search_categories_area);
with:
public void searchPressed(View v) {
if (!searchbox_expanded) {
my_relative_layout.setVisibility(View.VISIBLE);
searchbox_expanded = true;
} else {
my_relative_layout.setVisibility(View.GONE);
searchbox_expanded = false;
}
}
Well the expanding is really smooth animation, but the collapsing is not animated.
I have used other solutions online but I have not reached the desire effect due to the complex layout I think. Any solutions will be appreciated.
This is quite simple :
To collapse the view you only need to add an onClickListener on the parent view (search_box) which triggers a function to collapse the view with an animation.
To expand the view you need to trigger another animation to expend the view when clicking on the search EditText
Here is an example of animation to collapse and to expend a view:
` import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
/**
* Created by wajdichamakhi on 26/01/15.
*/
public class ResizeAnimation extends Animation {
private int endHeight; // distance between start and end height
private int endWidth; // distance between start and end width
private View view;
/**
* constructor, do not forget to use the setParams(int, int) method before
* starting the animation
*
* #param v
*/
public ResizeAnimation(View v) {
this.view = v;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
view.getLayoutParams().height = (int) (view.getHeight() + (endHeight - view.getHeight()) * interpolatedTime);
view.getLayoutParams().width = (int) (view.getWidth() + (endWidth - view.getWidth()) * interpolatedTime);
view.requestLayout();
}
/**
* set the starting and ending height for the resize animation
* starting height is usually the views current height, the end height is the height
* we want to reach after the animation is completed
*
* #param endWidths width in pixels
* #param endHeight height in pixels
*/
public void setParams(int endWidths, int endHeight) {
this.endWidth = endWidths;
this.endHeight = endHeight;
}
/**
* set the duration for the hideshowanimation
*/
#Override
public void setDuration(long durationMillis) {
super.setDuration(durationMillis);
}
#Override
public boolean willChangeBounds() {
return true;
}
/**
* Verify if this animation needs to be fired or not.
*/
public boolean isValidAnimation() {
if (this.endWidth == view.getWidth() && this.endHeight == view.getHeight())
return false;
else
return true;
}
}`
Now you put the function that returns a set of animation which contains this animation. I work with animation set so I can add several animation at once to the view and create a cool animation.
public AnimationSet getExpend_CollapseAnimationSet(final View v, int height, int width) {
AnimationSet animationSet = new AnimationSet(true);
ResizeAnimation resizeAnimation = new ResizeAnimation(v);
resizeAnimation.setParams(
width,
height);
if (resizeAnimation.isValidAnimation()) {
resizeAnimation.setDuration(ANIMATION_DURATION);
animationSet.addAnimation(resizeAnimation);
}
return animationSet;
}
Now use this function in your listeners with the right width and height
AnimationSet initialStateAnimation = getExpend_CollapseAnimationSet(myViewToExpend_Collapse,deiredHeight, desiredWidth);
myViewToExpend_Collapse.startAnimation(initialStateAnimation);
I have been trying to implement an animation on a relativeLayout. The animation works fine but after the animation is complete the edittext and the imageview inside the relative layout stops responding to any kind of user activity.
<LinearLayout 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:orientation="vertical" >
<RelativeLayout
android:id="#+id/rl_maincontroller_mainLayout"
android:layout_width="match_parent"
android:layout_height="380dp"
android:background="#color/button_color" >
<ImageView
android:id="#+id/iv_maincontroller_backImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_centerVertical="true"
android:src="#drawable/back" />
<EditText
android:id="#+id/tv_searchBox"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_toRightOf="#+id/iv_maincontroller_backImage"
android:background="#android:color/white"
android:drawableLeft="#drawable/search"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:layout_centerVertical="true"
android:hint="#string/search"
android:paddingLeft="10dp"
android:textColor="#android:color/black"
android:textColorHint="#color/grey"
android:textSize="17sp" />
</RelativeLayout>
</LinearLayout>
Before the animation the controls on the widgets work fine, the animation changes the parent relative layout from height 380 to 120 and after that the widgets become dead to any kind of user activity. I cannot control them. Can anyone please suggest an answer. Need it very urgently, have been stuck in it for hours.
The code for animating the layout is put below. I got it from a link and it worked as I wanted the animation to work but the widgets inside the layout became dead.
public class ResizeAnimation extends Animation {
private int startHeight;
private int deltaHeight; // distance between start and end height
private View view;
/**
* constructor, do not forget to use the setParams(int, int) method before
* starting the animation
* #param v
*/
public ResizeAnimation (View v) {
this.view = v;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
view.getLayoutParams().height = (int) (startHeight + deltaHeight * interpolatedTime);
view.requestLayout();
}
/**
* set the starting and ending height for the resize animation
* starting height is usually the views current height, the end height is the height
* we want to reach after the animation is completed
* #param start height in pixels
* #param end height in pixels
*/
public void setParams(int start, int end) {
this.startHeight = start;
deltaHeight = end - startHeight;
}
/**
* set the duration for the hideshowanimation
*/
#Override
public void setDuration(long durationMillis) {
super.setDuration(durationMillis);
}
#Override
public boolean willChangeBounds() {
return true;
}
Then I call this class as follows:
ResizeAnimation a = new ResizeAnimation(layout);
a.setDuration(500);
a.setParams(oldHeight, newHeight);
layout.startAnimation(a);
I have a simple button in my layout. Setting leftMargin to the view actually showing different results.
my_layout.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/left_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="hello pandora"/>
</RelativeLayout>
In my activity, I'm setting the leftMargin property to the Button.
Button leftBtn = (Button) findViewById(R.id.left_btn);
LayoutParams params = (LayoutParams) leftBtn.getLayoutParams();
params.leftMargin = 550;
If I set leftMargin as negative value or 0, its working fine, but If I set the value greater than the width of screen, it just resizing/compressing the button. I am expecting the button to go out of bounds like negative value.
I am expecting the button in the 3rd image to go out of bounds like the button in 1st image.
Please don't say to set the button layout_alignParentRight="true" in layout and rightMargin = -50in activity(this works) because I want to move the button from left to right.
I assume assigning a specific width larger than the screen size (eg. 1000 dp) to the parent RelativeLayout should solve your problem.
Also why do you want to make out-of-screen UI elements? What is the desired behaviour? Perhaps a transition animation would be better?
EDIT
I've tried the animation + storing the measured width of the Button. It seems to work.
Can you try this on GB?
MainActivity.java
public class MainActivity extends Activity {
final Context context = this;
Button mButton;
int mButtonWidth; // Measured width of Button
int amountToMove; // Amount to move the button in the x direction
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
amountToMove = 600;
mButton = (Button) findViewById(R.id.button);
// Measure Button's width
mButton.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
mButtonWidth = mButton.getMeasuredWidth();
// Simple onClick listener showing a Toast
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context,"Hello Pandora clicked!",Toast.LENGTH_SHORT).show();
}
});
// Onclick listener for the other button
Button toggle = (Button) findViewById(R.id.toggle);
toggle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Animate the other button
TranslateAnimation a = new TranslateAnimation(0, amountToMove, 0, 0);
a.setDuration(1000);
// Finalize movement when animation ends
a.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mButton.getLayoutParams();
// Restore measured width and change left margin
lp.width = mButtonWidth;
lp.leftMargin = lp.leftMargin + amountToMove;
mButton.setLayoutParams(lp);
amountToMove = -amountToMove;
}
#Override
public void onAnimationStart(Animation animation) { /* Do nothing */ }
#Override
public void onAnimationRepeat(Animation animation) { /* Do nothing */ }
});
mButton.startAnimation(a);
}
});
}
}
activity_main.xml
<LinearLayout 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:orientation="vertical"
tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Pandora"
android:id="#+id/button" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Move the other button"
android:id="#+id/toggle"/>
</LinearLayout>
EDIT 2
It works on a GB Emulator too (the Button gets clipped, is clickable).
u can use max line=1 to show complete text in one line on button when you use leftMargin = 550;
try this
<Button
android:id="#+id/left_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:maxLines="1"
android:text="hello pandora"/>
Hello Edit your button property like this,
android:layout_gravity="center_horizontal"
android:singleLine="true"
and change parent layout to frameLayout
I'm try to zoom a FrameLayout with the following example from der android developers site: http://developer.android.com/training/animation/zoom.html
My concrete Problem, in the first time the animation is right, is expand from the thumbView, in the second time the animation comes from 'somewhere' (middle/top to the center).
i have nearly the same, the differents are, i have an Framelayout instead an ImageView and i extract the function to minimize the View back in an extra Method. now thats looks like so:
private void zoomImageFromThumb(final View thumbView) {
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
// here i building my custome layout
startBounds = new Rect();
final Rect finalBounds = new Rect();
final Point globalOffset = new Point();
thumbView.getGlobalVisibleRect(startBounds);
findViewById(R.id.container)
.getGlobalVisibleRect(finalBounds, globalOffset);
startBounds.offset(-globalOffset.x, -globalOffset.y);
finalBounds.offset(-globalOffset.x + 15, -globalOffset.y + 60);
float startScale;
if ((float) finalBounds.width() / finalBounds.height()
> (float) startBounds.width() / startBounds.height()) {
startScale = (float) startBounds.height() / finalBounds.height();
float startWidth = startScale * finalBounds.width();
float deltaWidth = (startWidth - startBounds.width()) / 2;
startBounds.left -= deltaWidth;
startBounds.right += deltaWidth;
} else {
startScale = (float) startBounds.width() / finalBounds.width();
float startHeight = startScale * finalBounds.height();
float deltaHeight = (startHeight - startBounds.height()) / 2;
startBounds.top -= deltaHeight;
startBounds.bottom += deltaHeight;
}
thumbView.setAlpha(0f);
expandedImageView.setVisibility(View.VISIBLE);
expandedImageView.setPivotX(0f);
expandedImageView.setPivotY(0f);
AnimatorSet set = new AnimatorSet();
set
.play(ObjectAnimator.ofFloat(expandedImageView, View.X,
startBounds.left, finalBounds.left))
.with(ObjectAnimator.ofFloat(expandedImageView, View.Y,
startBounds.top, finalBounds.top))
.with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X,
startScale, 1f)).with(ObjectAnimator.ofFloat(expandedImageView,
View.SCALE_Y, startScale, 1f));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mCurrentAnimator = null;
}
#Override
public void onAnimationCancel(Animator animation) {
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
}
the startBounds Variable is global, cause i need this to know where the position is for the minimize process. Here the minimize Method:
private void minimizeViewFromThumb(final View thumbView) {
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
AnimatorSet set = new AnimatorSet();
set.play(ObjectAnimator
.ofFloat(expandedImageView, View.X, startBounds.left))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.Y,startBounds.top))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.SCALE_X, startScaleFinal))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.SCALE_Y, startScaleFinal));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
#Override
public void onAnimationCancel(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
}
if i debug this whole process i can see that the method getGlobalVisibleRect from the method zoomViewFromThumb give me another value.
if i debug the line
finalBounds.offset(-globalOffset.x, -globalOffset.y);
in the first time the two parameters are 0 and -60 and in the second time (after minimize and recreate there are 15 and 360.
i have no idea why thats happen.
i have try to set the View.X and View.Y parameter append from the given thumbView, i have try to work with constant Values for the View.X, View.Y parameter in the ObjectAnimator but nothing fix my problem.
now please help me.
Greets Manu
1. EDIT: the fail is on Android Version 4.1.2 i have test it in the emulator with Android 4.0 and there it works fine
2. EDIT: Here are the xml files, the first one is the xml File that representing my main Activity (with the animation), the second one represent the TableLayout what i push in the FrameLayout of the main xml. (Please notice, currently I'm at work and i have no access to the original, now these xml files are good as far I can remember)
the first
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/relZoom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/frameZoomOne"
android:layout_width="160dp"
android:layout_height="215dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp" >
</FrameLayout>
<FrameLayout
android:id="#+id/frameZoomTwo"
android:layout_width="160dp"
android:layout_height="215dp"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp" >
</FrameLayout>
<FrameLayout
android:id="#+id/container"
android:layout_width="300dp"
android:layout_height="408dp"
android:visibility="invisible" >
</FrameLayout>
<FrameLayout
android:id="#+id/containerTwo"
android:layout_width="300dp"
android:layout_height="408dp"
android:visibility="invisible" >
</FrameLayout>
</RelativeLayout>
the second
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/tableLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TableRow
android:id="#+id/tableRow1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip" >
<TextView
android:id="#+id/textView1"
android:text="Column 1"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/textView2"
android:text="Column 2"
android:textAppearance="?android:attr/textAppearanceLarge" />
</TableRow>
<TableRow
android:id="#+id/tableRow2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip" >
<ImageView
android:id="#+id/imgView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/android" />
</TableRow>
<TableRow
android:id="#+id/tableRow3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip" >
<TextView
android:id="#+id/textView3"
android:text="Column 3"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/textView4"
android:text="Column 4"
android:textAppearance="?android:attr/textAppearanceLarge" />
</TableRow>
</TableLayout>
3. EDIT: correct the xml file and now adding the Activity:
public class SinglePlayerSp extends Activity implements OnClickListener
{
private final Context mContext = this;
private boolean mBackZoomOne = false;
private FrameLayout frameZoomOne;
private FrameLayout frameZoomTwo;
private static Animator mCurrentAnimatorOne;
private int mShortAnimationDuration;
private float startScaleOne;
private static Animator mCurrentAnimatorTwo;
private float startScaleTwo;
private Rect startBoundsOne;
private Rect startBoundsTwo;
private static View lastViewOne;
private static View lastViewTwo;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_zoom);
frameZoomOne = (FrameLayout) findViewById(R.id.frameZoomOne);
frameZoomTwo = (FrameLayout) findViewById(R.id.frameZoomTwo);
frameZoomOne.setOnClickListener(this);
frameZoomTwo.setOnClickListener(this);
mShortAnimationDuration = getResources().getInteger(android.R.integer.config_mediumAnimTime);
cardItems = getIntent().getParcelableArrayListExtra(CARD_ITEMS);
java.util.Collections.shuffle(cardItems);
}
private void flipCard(boolean playerOneDeck, final int selectionFromPlayer, final boolean result)
{
Card cardItemOne = null;
if (oneCards.get(0) != null)
{
cardItemOne = oneCards.get(0);
}
if (!mBackZoomOne)
{
getFragmentManager().beginTransaction().setCustomAnimations(R.animator.card_flip_right_in,
R.animator.card_flip_right_out, R.animator.card_flip_left_in, R.animator.card_flip_left_out).replace(
R.id.frameZoomOne, new CardBackFragment()).commit();
mBackZoomOne = true;
}
else
{
getFragmentManager().beginTransaction().setCustomAnimations(R.animator.card_flip_right_in,
R.animator.card_flip_right_out, R.animator.card_flip_left_in, R.animator.card_flip_left_out).replace(
R.id.frameZoomOne,
CardFrontFragment.newInstance(cardItemPlayerOne, selectionFromPlayer, playerOneDeck)).commit();
mBackZoomOne = false;
zoomViewOneFromThumb(frameZoomOne, cardItemOne);
}
}
private void zoomViewOneFromThumb(final View thumbView, final Card cardItem)
{
if (mCurrentAnimatorOne != null)
{
mCurrentAnimatorOne.cancel();
}
lastViewOne = thumbView;
View.getDefaultSize(0, 0);
final FrameLayout expandFrameLayout = (FrameLayout) findViewById(R.id.container);
LayoutInflater inflater =
(LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.fragment_card_front_clickable, null);
TableRow rowOne = (TableRow) layout.findViewById(R.id.tableRow1);
rowOne.setOnClickListener(this);
TextView cardone = (TextView) layout.findViewById(R.id.textView1);
TextView cardtwo = (TextView) layout.findViewById(R.id.textView2);
TextView cardthree = (TextView) layout.findViewById(R.id.textView3);
TextView cardfour = (TextView) layout.findViewById(R.id.textView4);
Locale locale = getApplicationContext().getResources().getConfiguration().locale;
cardone.setText(cardItem.TextOne());
cardtwo.setText(cardItem.getTextTwo());
cardthree.setText(cardItem.getTextThree());
cardfour.setText(cardItem.TextFour());
expandFrameLayout.addView(layout);
startBoundsOne = new Rect();
final Rect finalBounds = new Rect();
final Point globalOffset = new Point();
thumbView.getGlobalVisibleRect(startBoundsOne);
findViewById(R.id.containerSp).getGlobalVisibleRect(finalBounds, globalOffset);
startBoundsOne.offset(-globalOffset.x, -globalOffset.y);
finalBounds.offset(-globalOffset.x + 15, -globalOffset.y + 50);
if ((float) finalBounds.width() / finalBounds.height() > (float) startBoundsOne.width()
/ startBoundsOne.height())
{
startScaleOne = (float) startBoundsOne.height() / finalBounds.height();
float startWidth = startScaleOne * finalBounds.width();
float deltaWidth = (startWidth - startBoundsOne.width()) / 2;
startBoundsOne.left -= deltaWidth;
startBoundsOne.right += deltaWidth;
}
else
{
startScaleOne = (float) startBoundsOne.width() / finalBounds.width();
float startHeight = startScaleOne * finalBounds.height();
float deltaHeight = (startHeight - startBoundsOne.height()) / 2;
startBoundsOne.top -= deltaHeight;
startBoundsOne.bottom += deltaHeight;
}
thumbView.setAlpha(0f);
expandFrameLayout.setVisibility(View.VISIBLE);
expandFrameLayout.setPivotX(0f);
expandFrameLayout.setPivotY(0f);
AnimatorSet set = new AnimatorSet();
set.play(ObjectAnimator.ofFloat(expandFrameLayout, View.X, startBoundsOne.left, finalBounds.left)).with(
ObjectAnimator.ofFloat(expandFrameLayout, View.Y, startBoundsOne.top, finalBounds.top)).with(
ObjectAnimator.ofFloat(expandFrameLayout, View.SCALE_X, startScaleOne, 1f)).with(
ObjectAnimator.ofFloat(expandFrameLayout, View.SCALE_Y, startScaleOne, 1f));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter()
{
#Override
public void onAnimationEnd(Animator animation)
{
mCurrentAnimatorOne = null;
}
#Override
public void onAnimationCancel(Animator animation)
{
mCurrentAnimatorOne = null;
}
});
set.start();
mCurrentAnimatorOne = set;
startScaleFinal = startScaleOne; // with this or without this, i have the same problem
}
private void minimizeViewOne(final View expandFrameLayout)
{
AnimatorSet set = new AnimatorSet();
set.play(ObjectAnimator.ofFloat(expandFrameLayout, View.X, startBoundsOne.left)).with(
ObjectAnimator.ofFloat(expandFrameLayout, View.Y, startBoundsOne.top)).with(
ObjectAnimator.ofFloat(expandFrameLayout, View.SCALE_X, startScaleFinal)).with(
ObjectAnimator.ofFloat(expandFrameLayout, View.SCALE_Y, startScaleFinal));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter()
{
#Override
public void onAnimationEnd(Animator animation)
{
lastViewOne.setAlpha(1f);
expandFrameLayout.setVisibility(View.GONE);
mCurrentAnimatorOne = null;
}
#Override
public void onAnimationCancel(Animator animation)
{
lastViewOne.setAlpha(1f);
expandFrameLayout.setVisibility(View.GONE);
mCurrentAnimatorOne = null;
}
});
set.start();
mCurrentAnimatorOne = set;
}
}
OK that's now the full code. At the End is an onClick Method, in there I receive user actions. from there I call the minimizeView Method, then some checks, after this I call the flipCard. That's all.
As per google Developer:
getGlobalVisibleRect(Rect r, Point globalOffset);
If some part of this view is not clipped by any of its parents, then return that area in r in global (root) coordinates.
ex:
thumbView.getGlobalVisibleRect(startBounds);
here suppose thumbview has width of 100 and height 75 and marging from left and and top 16 and 51 respectively this method store value in startBound(Rect) as left 16 , top 51 , right 16+100 = 116 , bottom 51+75 = 126. i.e. (16 , 51 , 116 , 126)
im not sure where you are assigning the event to close the view. but i would say that the point that is causing the error, is where you read some variables such as startScaleFinal = startScale; that has to be done before the enlarge animation start and proabaly others.
ill post my full working example with the diferent functions, and frameviews:
It is working perfectly.
activity:
/*
* Copyright 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.animationsdemo;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
/**
* A sample showing how to zoom an image thumbnail to full-screen, by animating the bounds of the
* zoomed image from the thumbnail bounds to the screen bounds.
*
* <p>In this sample, the user can touch one of two images. Touching an image zooms it in, covering
* the entire activity content area. Touching the zoomed-in image hides it.</p>
*/
public class ZoomActivity extends FragmentActivity {
/**
* Hold a reference to the current animator, so that it can be canceled mid-way.
*/
private Animator mCurrentAnimator;
/**
* The system "short" animation time duration, in milliseconds. This duration is ideal for
* subtle animations or animations that occur very frequently.
*/
private int mShortAnimationDuration;
final Rect finalBounds = new Rect();
final Point globalOffset = new Point();
final Rect startBounds = new Rect();
float startScale;
FrameLayout expandedImageView;
float startScaleFinal ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_zoom);
// Hook up clicks on the thumbnail views.
final View thumb1View = findViewById(R.id.thumb_button_1);
thumb1View.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
zoomImageFromThumb(thumb1View, R.drawable.image1);
}
});
final View thumb2View = findViewById(R.id.thumb_button_2);
thumb2View.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
zoomImageFromThumb(thumb2View, R.drawable.image2);
}
});
// Retrieve and cache the system's default "short" animation time.
mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime);
}
private void zoomImageFromThumb(final View thumbView, int imageResId) {
// If there's an animation in progress, cancel it immediately and proceed with this one.
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
// Load the high-resolution "zoomed-in" image.
expandedImageView = (FrameLayout) findViewById(R.id.expanded_image);
// The start bounds are the global visible rectangle of the thumbnail, and the
// final bounds are the global visible rectangle of the container view. Also
// set the container view's offset as the origin for the bounds, since that's
// the origin for the positioning animation properties (X, Y).
thumbView.getGlobalVisibleRect(startBounds);
findViewById(R.id.container).getGlobalVisibleRect(finalBounds, globalOffset);
startBounds.offset(-globalOffset.x, -globalOffset.y);
finalBounds.offset(-globalOffset.x, -globalOffset.y);
// Adjust the start bounds to be the same aspect ratio as the final bounds using the
// "center crop" technique. This prevents undesirable stretching during the animation.
// Also calculate the start scaling factor (the end scaling factor is always 1.0).
if ((float) finalBounds.width() / finalBounds.height()
> (float) startBounds.width() / startBounds.height()) {
// Extend start bounds horizontally
startScale = (float) startBounds.height() / finalBounds.height();
float startWidth = startScale * finalBounds.width();
float deltaWidth = (startWidth - startBounds.width()) / 2;
startBounds.left -= deltaWidth;
startBounds.right += deltaWidth;
} else {
// Extend start bounds vertically
startScale = (float) startBounds.width() / finalBounds.width();
float startHeight = startScale * finalBounds.height();
float deltaHeight = (startHeight - startBounds.height()) / 2;
startBounds.top -= deltaHeight;
startBounds.bottom += deltaHeight;
}
// Hide the thumbnail and show the zoomed-in view. When the animation begins,
// it will position the zoomed-in view in the place of the thumbnail.
thumbView.setAlpha(0f);
expandedImageView.setVisibility(View.VISIBLE);
// Set the pivot point for SCALE_X and SCALE_Y transformations to the top-left corner of
// the zoomed-in view (the default is the center of the view).
expandedImageView.setPivotX(0f);
expandedImageView.setPivotY(0f);
// Construct and run the parallel animation of the four translation and scale properties
// (X, Y, SCALE_X, and SCALE_Y).
AnimatorSet set = new AnimatorSet();
set
.play(ObjectAnimator.ofFloat(expandedImageView, View.X, startBounds.left,
finalBounds.left))
.with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top,
finalBounds.top))
.with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X, startScale, 1f))
.with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_Y, startScale, 1f));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mCurrentAnimator = null;
}
#Override
public void onAnimationCancel(Animator animation) {
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
// Upon clicking the zoomed-in image, it should zoom back down to the original bounds
// and show the thumbnail instead of the expanded image.
startScaleFinal = startScale;
expandedImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
minimizeViewFromThumb(thumbView);
}
});
}
private void minimizeViewFromThumb(final View thumbView) {
// Upon clicking the zoomed-in image, it should zoom back down to the original bounds
// and show the thumbnail instead of the expanded image.
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
// Animate the four positioning/sizing properties in parallel, back to their
// original values.
AnimatorSet set = new AnimatorSet();
set
.play(ObjectAnimator.ofFloat(expandedImageView, View.X, startBounds.left))
.with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top))
.with(ObjectAnimator
.ofFloat(expandedImageView, View.SCALE_X, startScaleFinal))
.with(ObjectAnimator
.ofFloat(expandedImageView, View.SCALE_Y, startScaleFinal));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
#Override
public void onAnimationCancel(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
}
}
layout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView style="?android:textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/message_zoom_touch_expand" />
<!-- This is an example layout containing thumbnail image buttons that, when pressed,
zoom in to show more detail. All of the zooming and animation logic is in
the ZoomActivity class. -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="horizontal">
<!-- These buttons don't have any decorations (3D bevel, etc.), but it's still
important to show feedback on touch or focus. The custom
"ToughHighlightImageButton" ImageButton subclass helps achieve this by drawing
the standard system "pressed" and "focused" overlay upon user interaction. -->
<FrameLayout
android:id="#+id/thumb_button_1"
android:layout_width="100dp"
android:layout_height="75dp"
android:background="#android:color/holo_orange_light"
android:contentDescription="#string/description_image_2" />
<FrameLayout
android:id="#+id/thumb_button_2"
android:layout_width="100dp"
android:layout_height="75dp"
android:background="#android:color/darker_gray"
android:contentDescription="#string/description_image_2" />
</LinearLayout>
</LinearLayout>
<!-- This initially-hidden ImageView will hold the expanded/zoomed version of the
images above. Without transformations applied, it takes up the entire screen.
To achieve the "zoom" animation, this view's bounds are animated from the
bounds of the thumbnail buttons above, to its final laid-out bounds. The implementation
of this animation is in the ZoomActivity class. -->
<FrameLayout
android:id="#+id/expanded_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
android:background="#android:color/holo_blue_light" />
</FrameLayout>