Shared element and circular reveal - android

I would like to make an animation similar to what we can find in the Play Store: https://www.youtube.com/watch?v=B5hBViIzw5Y
I already know how to have shared element between activities and how to make circular reveal, but I'm struggling to do everything in order!
Here is where I am so far, the effect is not so bad, but after the circular reveal (to hide the item) there is a little time before it starts the intent.
My item :
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/card_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardUseCompatPadding="true"
card_view:cardCornerRadius="2dp">
<RelativeLayout
android:id="#+id/secondary_back"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#color/colorPrimary"
android:visibility="gone">
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:visibility="visible">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true">
<de.hdodenhof.circleimageview.CircleImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/shared_element"
android:transitionName="shared"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="#drawable/shared_color"
android:visibility="gone"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="#+id/primary_back"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#drawable/ripple_background_rounded">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp">
<de.hdodenhof.circleimageview.CircleImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_image"
android:layout_width="85dp"
android:layout_height="85dp"
app:civ_border_width="3dp"
app:civ_border_color="#color/colorPrimary"/>
</LinearLayout>
<TextView
android:id="#+id/card_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textColor="#android:color/black"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="24dp"
android:paddingBottom="24dp"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
and my function to launch everything :
private void launchAnimation(View v, final int position) {
// previously visible view
final View myView = v.findViewById(R.id.primary_back);
final View background = v.findViewById(R.id.secondary_back);
// my shared element
final CircleImageView sharedElement = (CircleImageView) v.findViewById(R.id.shared_element);
// get the center for the clipping circle
int cx = myView.getWidth() / 2;
int cy = myView.getHeight() / 2;
// get the initial radius for the clipping circle
float initialRadius = (float) Math.hypot(cx, cy);
// create the animation (the final radius is zero)
final Animator anim =
ViewAnimationUtils.createCircularReveal(background, cx, cy, initialRadius, 0);
// fade in background
final Animation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator()); //add this
fadeIn.setDuration(200);
final Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setInterpolator(new AccelerateInterpolator()); //and this
fadeOut.setDuration(200);
// make the view invisible when the animation is done
anim.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
}
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
background.setVisibility(View.GONE);
Intent intent = new Intent(context, ResultActivity.class);
// Pass data object in the bundle and populate details activity.
intent.putExtra(ResultActivity.EXTRA_POSITION, position);
ActivityOptionsCompat options = ActivityOptionsCompat.
makeSceneTransitionAnimation(activity, sharedElement, "shared");
activity.startActivity(intent, options.toBundle());
}
});
background.setVisibility(View.VISIBLE);
background.startAnimation(fadeIn);
myView.startAnimation(fadeOut);
fadeIn.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
anim.start();
}
#Override
public void onAnimationEnd(Animation animation) {
myView.setVisibility(View.GONE);
sharedElement.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
If someone knows how to simplify this animation that would be so helpful. Thanks a lot.

For everyone who might want to make this kind of animation, I found an article about this exact transition.
At the end of this article there is the project archive who helped me a lot to make it work.

Related

Flickers while layout visible/gone

Is there any way to hide a view without flickering its above view?
I am trying to hide a View below MapView. Once I set its visibility to GONE, MapView flickers. As I have to add more markers dynamically, couldn't able to keep MapView and bottomView in FrameLayout, since the bottomView will hide those markers in small size screens.
Layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true">
<com.myapp.widgets.MapPlacePicker
android:id="#+id/lay_fr_map_inc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/options_layout" />
<LinearLayout
android:id="#+id/options_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:animateLayoutChanges="true"
android:background="#FFFFFF"
android:orientation="vertical"
android:visibility="visible">
<com.myapp.widgets.FontTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:text="Please select a location!!"
android:textAppearance="#android:style/TextAppearance.Small" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.aigestudio.wheelpicker.WheelPicker
android:id="#+id/main_option_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_weight="0.5"
app:wheel_atmospheric="true"
app:wheel_curved="false"
app:wheel_item_space="15dp"
app:wheel_item_text_color="#ffafafaf"
app:wheel_item_text_size="12dp"
app:wheel_selected_item_text_color="#color/colorPrimary"
app:wheel_visible_item_count="3" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
Output:
I have also tried TranslationAnimation, but no luck. Its showing more gray space than before.
int fromY = (visibility == View.GONE) ? 0 : optionLayout.getHeight();
int toY = (visibility == View.GONE) ? optionLayout.getHeight() : 0;
if (visibility == View.VISIBLE) {
optionLayout.setVisibility(visibility);
}
TranslateAnimation animate = new TranslateAnimation(
0, // fromXDelta
0, // toXDelta
fromY, // fromYDelta
toY); // toYDelta
animate.setDuration(1000);
animate.setInterpolator(new AccelerateDecelerateInterpolator());
//animate.setFillAfter(false);
animate.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
if (visibility == View.GONE)
optionLayout.setVisibility(visibility);
optionLayout.clearAnimation();
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
optionLayout.startAnimation(animate);
I don't see any flickering in that animation; if you want to avoid the vertical resizing behavior of lay_fr_map_inc then you can just remove this attribute:
android:layout_above="#+id/options_layout"
...and maybe make the height match_parent. Then, lay_fr_map_inc will stay full height, but the bottom portion will be hidden by options_layout when it appears (instead of scooting upwards).
Don't forget to change the map padding when you do this, so you don't obscure the Google logo (which is a violation of the rules): setPadding()

Animate LinearLayout when keyboard goes up/down

I have a layout like this:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="25dp"
android:paddingRight="25dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView"
android:background="#drawable/logo" />
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView ... />
<EditText ... />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView ... />
<EditText ... />
</LinearLayout>
</LinearLayout>
<Button ... />
</LinearLayout>
I want to fade out the ImageView and move the second (inner) LinearLayout up (near the top of the screen) when the keyboard comes up and then do the opposite when the keyboard goes back down.
How can I achieve this?
Use TranslateAnimation class to animate your view.
Animation slide = new TranslateAnimation(fromX,toX,fromY,toY);
slide.setDuration(300);//here you can set your own duration of animation in ms.
yourView.startAnimation(slide);
You can also override some callbacks.
slide.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
There is no direct way of finding out whether android softkey pad is opne or not . But you can do a work around and calculate the size diff between your activity's view root and the window size. There are many ways to do it, one way that i found was this:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
... do something here
}
}
});

Android - TextView with 'zero' height

I would to set dinamically the TextView height with an ObjectAnimator.
This is the code:
if(condition){
height = 136;
}else{
height = 0;
}
ObjectAnimator animator = ObjectAnimator.ofInt(
mText,
"height",
height
).setDuration(400);
animator.start();
This works, somwhere, but it doesn't set the TextView height to 0, but about 80px.
Why?
To hide and show textview, It is not good practice to set its heights instead do this:
textview.setVisibility(View.GONE);
OR
textview.setVisibility(View.INVISIBLE);
View.GONE This view is invisible, and it doesn't take any space for layout purposes.
View.INVISIBLE This view is invisible, but it still takes up space for layout purposes.
To make it Visible again, use
textview.setVisibility(View.VISIBLE);
EDITED
To hide view with animation,
ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", 0.0f);
anim.addListener(new AnimatorListener() {
...
#Override
public void onAnimationEnd(Animator animation) {
animDrawable.stop()
}
...
});
anim.setDuration(300).start();
This will gradually fade your view and hide it with animation.
If you want to hide the TextView with animation, use below code
ViewPropertyAnimator mTextAnimator = myTextView.animate()
.scaleY(0f)
.setListener(new Animator.AnimatorListener() {
public void onAnimationStart(Animator animation) {}
public void onAnimationRepeat(Animator animation) {}
public void onAnimationCancel(Animator animation) {}
public void onAnimationEnd(Animator animation) {
myTextView.setVisibility(View.GONE);
}
})
.setDuration(400);
mTextAnimator.start();
To show TextView with animation, use
mTextAnimator = myTextView.animate()
.scaleY(1f)
.setListener(null)
.setDuration(400);
mTextAnimator.start();
I assume you are trying to hide it by setting height to 0? If this is the case, why not use .setVisibility(View.GONE)?
If you have other views depending on its location then use setVisibility(View.INVISIBLE). Otherwise use setVisibility(View.GONE).
In my .xml file, I used android:visibility="gone". Originally I had this:
<TextView
android:id="#+id/labelReachable"
android:layout_width="wrap_content"
android:gravity="left"
android:textSize="15dp"
android:layout_marginTop="10dp"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:text="Reachability"></TextView>
<ImageView
android:background="#drawable/bar_dark"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="#+id/insertPings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical" >
</LinearLayout>
I wanted to make those elements invisible and not take any space for layout purposes. I simply used android:visibility="gone" to have this:
<TextView
android:id="#+id/labelReachable"
android:layout_width="wrap_content"
android:gravity="left"
android:textSize="15dp"
android:layout_marginTop="10dp"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:visibility="gone"
android:text="Reachability"></TextView>
<ImageView
android:background="#drawable/bar_dark"
android:layout_width="fill_parent"
android:visibility="gone"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="#+id/insertPings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:visibility="gone"
android:orientation="vertical" >
</LinearLayout>

Add animation when hide "LinearLayout" (View.GONE) and show LinearLayout (View.VISIBLE)

Sorry for my English... I will try to explain what I want to do.
I have a project. It can be downloaded at the link:
https://drive.google.com/file/d/0Bxhi0uFKK3upcXJjNGtMVkg4TDQ/view?usp=sharing
As you can see the screenshot:
http://pixs.ru/showimage/Screenshot_9509352_15647059.png
The button "Hide/Show B layout" hides and shows the green container - "B layout". I want add animation top down when the container "B layout" is showing. And the animation from the bottom up when the container is hidden. Also, I want the blue container "C", gradually fell together with the container "B". And rising smoothly, together with the container "B". Please help me to do it.
Below duplicate my code:
MainActivity
public class MainActivity extends Activity {
View Layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Layout = findViewById(R.id.bLayout);
final View button2 = findViewById (R.id.button);
button2.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick (View v){
if ((Layout.getVisibility() == View.VISIBLE))
{
Layout.setVisibility(View.GONE);
}
else
{
// Animation animFadeIn = AnimationUtils.loadAnimation(getApplicationContext(), android.R.anim.slide_in_left);
// Layout.setAnimation(animFadeIn);
Layout.setVisibility(View.VISIBLE);
}
}
});
}
}
I found a solution to the problem. Full lesson and source code can be downloaded here: click here
Or use the code below:
activity_main.xml
<LinearLayout 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" >
<LinearLayout
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:background="#FCF"
android:orientation="horizontal" >
<TextView
android:id="#+id/color"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:background="#drawable/rectangle"
android:fontFamily="sans-serif-light"
android:gravity="center_vertical"
android:text=""
android:textAlignment="center"
android:textStyle="bold" />
<TextView
android:id="#+id/clickme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:fontFamily="sans-serif-light"
android:gravity="center_vertical"
android:text="click_here"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="#+id/expandable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:background="#FFF"
android:orientation="vertical"
android:paddingLeft="4dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Слуга: text3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text4" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text5" />
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity {
LinearLayout mLinearLayout;
LinearLayout mLinearLayoutHeader;
ValueAnimator mAnimator;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("title");
mLinearLayout = (LinearLayout) findViewById(R.id.expandable);
// mLinearLayout.setVisibility(View.GONE);
mLinearLayoutHeader = (LinearLayout) findViewById(R.id.header);
// Add onPreDrawListener
mLinearLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
mLinearLayout.getViewTreeObserver()
.removeOnPreDrawListener(this);
mLinearLayout.setVisibility(View.GONE);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(
0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec
.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
mLinearLayout.measure(widthSpec, heightSpec);
mAnimator = slideAnimator(0,
mLinearLayout.getMeasuredHeight());
return true;
}
});
mLinearLayoutHeader.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mLinearLayout.getVisibility() == View.GONE) {
expand();
} else {
collapse();
}
}
});
}
private void expand() {
// set Visible
mLinearLayout.setVisibility(View.VISIBLE);
mAnimator.start();
}
private void collapse() {
int finalHeight = mLinearLayout.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
mLinearLayout.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 = mLinearLayout
.getLayoutParams();
layoutParams.height = value;
mLinearLayout.setLayoutParams(layoutParams);
}
});
return animator;
}
}
I faced a similar issue and this is the easiest solution I could find:
setVisibility(View.GONE) on the view you wish to hide.
And make sure in the xml layout the parent has following attribute:
android:animateLayoutChanges="true"
I think you can easily do this by using the AlphaAnimation class. Here is a similar question with an answer.
So I think what you're looking for is how to hook up translate animations to show/hide a view as opposed to just setting the visibility instantly.
Take a look at Show and hide a View with a slide up/down animation. Instead of just setting the visibility, first you run the translate animations, then add the hooks to show or hide the view after they're finished.
If you find that the bottom view is not moving, jump into your Android developer options and enable "Show layout bounds" then you can see the borders for views (animations don't move the actual view bounds). To get the bottom view to animate as well it will also need an translate animation.

Scrollview not resizing

I am using pinch zoom to just horizontaly zoom my custom view. It works fine, but the outside scroll view is not resizing with its content, and there are ugly blank space arround the view.
My Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<AbsoluteLayout
android:id="#+id/wrapper"
android:layout_width="wrap_content"
android:layout_height="0px"
android:layout_weight="1">
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:fillViewport="true"
android:id="#+id/scrollview">
<Auda.WaveFormView
android:id="#+id/waveform"
android:layout_height="fill_parent"
android:layout_width="2000dp"
android:layout_weight="1" />
</HorizontalScrollView>
</AbsoluteLayout>
<LinearLayout
style="#style/ToolbarBackground"
android:layout_width="fill_parent"
android:layout_height="62dip"
android:gravity="center">
<ImageButton
android:id="#+id/play"
android:layout_width="71dip"
android:layout_height="52dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
style="#android:style/MediaButton"
android:src="#android:drawable/ic_media_play" />
</LinearLayout>
My zooming code
ScaleAnimation scaleAnimation = new ScaleAnimation(1f / prevScale, 1f / mScale, 1, 1, 0, 0);
scaleAnimation.Duration = 0;
scaleAnimation.FillAfter = true;
this.view.StartAnimation (scaleAnimation);
Although your view is now (for example) drawn on half of the screen, it is really still occupying the full screen. You can verify this by adding a ClickListener to the view and trying to press the blank area you marked.
To solve this, you can add an AnimationListener to your ScaleAnimation. In the onAnimationEnd, simply update the LayoutParams of your Auda.WaveFormView. For example:
ScaleAnimation scaleAnimation = new ScaleAnimation(1f / prevScale, 1f / mScale, 1, 1, 0, 0);
scaleAnimation.Duration = 0;
scaleAnimation.FillAfter = true;
this.view.StartAnimation (scaleAnimation);
//after your are done with your animation
//set the animation listener
scaleAnimation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
//this might not be the right logic
//especially that you are using scales relative to prevScale
this.view.getLayoutParams().width = v.getWidth() / mScale;
}
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
});
Try to change the layout width to fill_parent instead of wrap content

Categories

Resources