Taganimation

Nice Shimmer library by Facebook

10734316_1115633315129045_1618068289_n

original post: https://code.facebook.com/posts/636856646421011/shimmer-for-android/

//DL

Honeycomb GMail animation mystery

There are a lot of questions on the Internet like these:

http://stackoverflow.com/questions/4817900/android-fragments-and-animation
http://stackoverflow.com/questions/5327636/animating-fragments-and-the-back-stack

GMail Honeycomb Android slide animation

If you are looking for a sample code – this post is for you.

Everybody wants to implement slide-in/slide-out animations like in GMail Tablet client. They try to use fragment animations (setCustomAnimations for FragmentTransaction). But if you take a deep look into GMail client implementation – they use LinearLayout and ObjectAnimator.

The code is quite simple – you just change left margin of the root view + change width of the right view.

package com.fragment.test;

import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.app.Activity;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;

public class FragmentAnimationTestActivity extends Activity implements Fragment2.FragmentResultListener {

    private static final TimeInterpolator sCollapseInterpolator = new DecelerateInterpolator(2.5F);

    private View mPanel1;
    private View mPanel2;
    private View mLayout;

    boolean isCollapsed;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mLayout = findViewById(R.id.l1);
        mPanel1 = findViewById(R.id.fragment1);
        mPanel2 = findViewById(R.id.fragment2);
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.fragment1, Fragment1.newInstance(), "f1");
        ft.replace(R.id.fragment2, Fragment2.newInstance(this), "f2");
        ft.commit();
    }

    public int getPanelLeft() {
        return ((ViewGroup.MarginLayoutParams) mLayout.getLayoutParams()).leftMargin;
    }

    public void setPanelLeft(int paramInt) {
        ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mLayout.getLayoutParams();
        lp.leftMargin = paramInt;
        mLayout.setLayoutParams(lp);
    }

    public int getPanel2W() {
        return ((ViewGroup.MarginLayoutParams) mPanel2.getLayoutParams()).width;
    }

    public void setPanel2W(int paramInt) {
        ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mPanel2.getLayoutParams();
        lp.width = paramInt;
        mPanel2.setLayoutParams(lp);
    }

    @Override
    public void onBtnClick() {
        if (isCollapsed) {
            PropertyValuesHolder[] arrayOfPropertyValuesHolder = new PropertyValuesHolder[2];
            arrayOfPropertyValuesHolder[0] = PropertyValuesHolder.ofInt("PanelLeft", -300, 0);
            arrayOfPropertyValuesHolder[1] = PropertyValuesHolder.ofInt("Panel2W", 1280, 980);
            ObjectAnimator localObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
                    arrayOfPropertyValuesHolder).setDuration(400);
            localObjectAnimator.setInterpolator(sCollapseInterpolator);
            localObjectAnimator.start();
        } else {
            PropertyValuesHolder[] arrayOfPropertyValuesHolder = new PropertyValuesHolder[2];
            arrayOfPropertyValuesHolder[0] = PropertyValuesHolder.ofInt("PanelLeft", 0, -300);
            arrayOfPropertyValuesHolder[1] = PropertyValuesHolder.ofInt("Panel2W", 980, 1280);
            ObjectAnimator localObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
                    arrayOfPropertyValuesHolder).setDuration(400);
            localObjectAnimator.setInterpolator(sCollapseInterpolator);
            localObjectAnimator.start();
        }
        isCollapsed = !isCollapsed;
    }

}

Of course, you can calculate all values dynamically. This is just a quick ugly sample. Full source code is available here.

Happy tabletting! 🙂

//DL

Horizontal slide gallery with pages

Imagine you want to create interactive horizontal slide gallery with paging (scroll left/right not one-by-one but pages).
Like this one:

Hopefully you can easily implement this with HorizontalScrollView. Since API level 3 it has method smoothScrollBy.

Your code may looks like:

public class TestUIActivity extends Activity {

	private GestureDetector gestureDetector = null;
	private HorizontalScrollView hs;

	private int mWidth = 1160;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		gestureDetector = new GestureDetector(new MyGestureDetector());
		hs = (HorizontalScrollView) findViewById(R.id.hs);
		hs.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (gestureDetector.onTouchEvent(event)) {
					return true;
				}
				if (event.getAction() == 1) {
					if (hs.getScrollX() > mWidth + mWidth / 2) {
						hs.smoothScrollBy(mWidth * 2 - hs.getScrollX(), 0);
					} else if (hs.getScrollX() > mWidth / 2) {
						hs.smoothScrollBy(mWidth - hs.getScrollX(), 0);
					} else {
						hs.smoothScrollBy(-hs.getScrollX(), 0);
					}
					return true;
				}
				return false;
			}
		});
	}

	class MyGestureDetector extends SimpleOnGestureListener {

		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
				float velocityY) {
			if (e1.getX() < e2.getX()) {
				moveLeft();
			} else {
				moveRight();
			}
			return true;
		}
	}

	private void moveRight() {
		if (hs.getScrollX() > 0 && hs.getScrollX() < mWidth) {
			hs.smoothScrollBy(mWidth - hs.getScrollX(), 0);
		} else if (hs.getScrollX() > mWidth && hs.getScrollX() < mWidth * 2) {
			hs.smoothScrollBy(mWidth * 2 - hs.getScrollX(), 0);
		}

	}

	private void moveLeft() {
		if (hs.getScrollX() > 0 && hs.getScrollX() < mWidth) {
			hs.smoothScrollBy(-hs.getScrollX(), 0);
		} else if (hs.getScrollX() > mWidth && hs.getScrollX() < mWidth * 2) {
			hs.smoothScrollBy(mWidth - hs.getScrollX(), 0);
		}

	}
}

and simple layout that you may construct from code:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent">
	<com.dlukashev.test.HorizontalScrollView
		android:id="@+id/hs"
		android:scrollbars="none"
		android:layout_width="1160dp"
		android:layout_height="wrap_content">
		<LinearLayout
			android:layout_width="wrap_content"
			android:layout_height="fill_parent">
			<!-- page1 -->
			<TextView
				android:id="@+id/id1"
				android:background="#FFFFFF"
				android:layout_marginLeft="10dp"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFFFF"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFFFF"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFFFF"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFFFF"
				android:layout_marginRight="20dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<!-- page2 -->
			<TextView
				android:background="#FF0000"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FF0000"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FF0000"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FF0000"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FF0000"
				android:layout_marginRight="20dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<!-- page3 -->
			<TextView
				android:background="#FFFF00"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFF00"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFF00"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFF00"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFF00"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
		</LinearLayout>
	</com.dlukashev.test.HorizontalScrollView>
</LinearLayout>

One sad detail that you cannot change view animation speed (DEFAULT_DURATION=250 in class OverScroller). But you can easily fix it by adding HorizontalScrollView, OverScroller, Scroller and EdgeGlow to your project.

You can find full sample with animation speed = 500 here. This sample is for tablet resolution – change layout and items sizes for the phone if you would like.

//DL

© 2017 Android Tales

Theme by Anders NorenUp ↑