87
Animate me ! #AnimateMe by(Mathias Seguy == Android2EE) { French Android Trainer}

Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Embed Size (px)

Citation preview

Page 1: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Animate me !

#AnimateMeby(Mathias Seguy == Android2EE){

French Android Trainer}

Page 2: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Animate me ! If you don't do it for me,

do it for chet !

Page 3: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Demonstration !

The Tutorial

Page 4: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Animation is lifeAnimation is comprehensionAnimation is engagements

Animation is delighted your UXAnimation is necessary

Animation is simple

Why animations?

Page 5: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Make Animations simple

Animations framework's goal ?

Page 6: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Because we want you to animate your

application !Chris Banes Bruno

OliveiraRoman Nurick

Adam Powell

Chet Haase Reto Meier Taylor Ling

Romain Guy

Animations framework's goal ?

Page 7: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Animations Elementary Principles

Page 8: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Alpha Rotate

TranslateScale

And the plan transformations are yours

V1

<set android:interpolator="@[package:]anim/interpolator_resource">    <alpha        android:duration="float" android:fromAlpha="float" android:toAlpha="float" />    <scale        android:duration="float"        android:fromXScale="float" android:toXScale="float"        android:fromYScale="float" android:toYScale="float"        android:pivotX="float" android:pivotY="float" />    <translate        android:duration="float"        android:fromXDelta="float" android:toXDelta="float"        android:fromYDelta="float" android:toYDelta="float" />    <rotate        android:duration="float"        android:fromDegrees="float" android:toDegrees="float"        android:pivotX="float" android:pivotY="float" />    <set>        ...    </set></set>

Animation animIn= AnimationUtils.loadAnimation(ctx, R.anim.generic_anim);edtMessage.startAnimation(animIn);

animation/generic_anim.xml

Only change pixels not the state of the view

What we know: Tween Animations

Page 9: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Makes animations generic

V11

/** * The in Animation for after HC */AnimatorSet animInHC;

animInHC = (AnimatorSet) AnimatorInflater.loadAnimator(ctx, R.animator.generic_anim);animInHC.setTarget(edtMessage);animInHC.setTarget(btnAdd);animInHC.start();

<set > <objectAnimator android:duration="1000" android:propertyName="translationX" android:valueFrom="-250" android:valueTo="0" android:valueType="floatType" />

<objectAnimator android:duration="1000" android:propertyName="scaleX" android:valueFrom="0.0" android:valueTo="1.0" android:valueType="floatType" /> </set>

animator-v11/generic_anim.xml

Changes the state of the object

What we know: ObjectAnimator

Page 10: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Uses Handler and RunnableSimple but dangerous (memory leak, runs in UI thread,

can generates frames drops)Not optimized

Animation is changing the view/object state by dropping changes in the UI thread

Handler clipDrawableHandler=new Handler();Runnable clipDrawableRunnable=new Runnable() { @Override

public void run() {myView.changeSomething(level);clipDrawableHandler.postDelayed(clipDrawableRunnable,32);

}};

V1

Animation: Elementary principles

Page 11: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Uses Handler and RunnableSimple but dangerous (memory leak, runs in UI thread,

can generates frames drops)Not optimized

V11

Animation is changing the view/object state by dropping changes in the UI thread

Animation: Elementary principles

Handler clipDrawableHandler=new Handler();Runnable clipDrawableRunnable=new Runnable() { @Override

public void run() {myView.changeSomething(level);clipDrawableHandler.postDelayed(clipDrawableRunnable,32);

}};

Have to be replaced by ObjectAnimator when

Gingerbread is out of scope

Page 12: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Make movement real :Interpolators are simple

Page 13: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Don't be scared, it's simple. How do you go from the point from to the point to ?

V1

t1t0v0

v1

from

to?i(t)=v,

where i(t0)=v0 and i(t1)=v1

float

time

Interpolators

Page 14: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

It can be straight

V1

t1t0v0

v1

from

to

linear

Interpolators

Page 15: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

t1t0v0

v1

You can use the system's ones

V1

t1t0v0

v1

from

to

deceleration acceleration

to

fromt1t0v0

v1to

bouncing

from

<set android:interpolator="@android:anim/accelerate_interpolator">

<set android:interpolator="@android:anim/decelerate_interpolator">

<set android:interpolator="@android:anim/

bounce_interpolator">

Interpolators

Page 16: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Or build your own.V1

t1t0v0

v1

from

to

alcoholicpublic class MyInterpolator implements Interpolator { float v; @Override public float getInterpolation(float input) { //v=i(input) return v; }...}

Interpolators

Page 17: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Drawables are our best friends

Page 18: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

myDrawable= (ImageView)findViewById(R.id.imvToto).getDrawable();

<ImageView android:id="@+id/imvToto" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:src="@drawable/my_drawable"/>

V1

Think Drawables

Page 19: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

ClipDrawableRotateDrawableScaleDrawable

AnimationDrawableTransitionDrawableStateListDrawable

AnimatedStateListDrawable

AnimatedVectorDrawableHandler clipDrawableHandler=new Handler();Runnable clipDrawableRunnable=new Runnable() {

@Override public void run() {level++;

clipDrawableHorizontal.setLevel(level); clipDrawableHandler.postDelayed(clipDrawableRunnable,32); }};

<?xml version="1.0" encoding="utf-8"?><clip xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/ic_android2ee" android:clipOrientation="horizontal" android:gravity="left" />

V1

Think Drawables

Page 20: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

RotateDrawable rotateDrawableWheel;Handler rotateDrawableHandler=new Handler();Runnable rotateDrawableRunnable=new Runnable() {public void run() {level++;

rotateDrawableWheel.setLevel(level);rotateDrawableHandler.postDelayed(rotateDrawableRunnable,32);

}};

<?xml version="1.0" encoding="utf-8"?><rotate xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/ic_android2ee" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="360" />

V1

ClipDrawableRotateDrawable

ScaleDrawableAnimationDrawableTransitionDrawableStateListDrawable

AnimatedStateListDrawable

AnimatedVectorDrawable

Think Drawables

Page 21: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

ScaleDrawable scaleDrawable;Handler scaleDrawableHandler=new Handler();Runnable scaleDrawableRunnable=new Runnable() {public void run() {level++;

scaleDrawable.setLevel(level);scaleDrawableHandler.postDelayed(scaleeDrawableRunnable,32);

}};

<?xml version="1.0" encoding="utf-8"?><scale xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@mipmap/ic_edit" android:scaleGravity="center" android:scaleHeight="100%" android:scaleWidth="100%" />

V1

ClipDrawableRotateDrawableScaleDrawable

AnimationDrawableTransitionDrawableStateListDrawable

AnimatedStateListDrawable

AnimatedVectorDrawable

Think Drawables

Page 22: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

animationDrawable.start();

<animation-list android:id="@+id/selected" android:oneshot="false"> <item android:drawable="@drawable/attack_magic1" android:duration="100" /> <item android:drawable="@drawable/attack_magic2" android:duration="100" /> <item android:drawable="@drawable/attack_magic3" android:duration="100" /> <item android:drawable="@drawable/attack_magic4" android:duration="100" /></animation-list>

ClipDrawableRotateDrawableScaleDrawable

AnimationDrawableTransitionDrawableStateListDrawable

AnimatedStateListDrawable

AnimatedVectorDrawable

V1

Think Drawables

Page 23: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

transitionDrawable.startTransition(3000); transitionDrawable.reverseTransition(3000);

<?xml version="1.0" encoding="utf-8"?><transition xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@mipmap/ic_ok" /> <item android:drawable="@mipmap/ic_nok" /></transition>

ClipDrawableRotateDrawableScaleDrawable

AnimationDrawableTransitionDrawable

StateListDrawableAnimatedStateListDrawa

bleAnimatedVectorDrawable

V1

Think Drawables

Page 24: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android" android:enterFadeDuration="300" android:exitFadeDuration="300"> <!--Sorry below v21 there is no animated selector you can just fade in and fade out--> <item android:id="@+id/item_pressed"

android:state_pressed="true"> <bitmap android:src="@drawable/ic_android2ee"/></item>

<item android:id="@+id/item_normal"> <bitmap android:src="@drawable/ic_nut"/> </item>

</selector>

fade fade

Normal

Pressed

Normal

View state

Display

V1

ClipDrawableRotateDrawableScaleDrawable

AnimationDrawableTransitionDrawable

StateListDrawableAnimatedStateListDrawa

bleAnimatedVectorDrawable

Think Drawables

Page 25: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

<?xml version="1.0" encoding="utf-8"?><animated-selector > <item android:id="@+id/item_pressed"

android:state_pressed="true"> <bitmap android:src="@drawable/ic_android2ee"/></item>

<item android:id="@+id/item_normal"> <bitmap android:src="@drawable/ic_nut"/> </item>

<transition android:fromId="@+id/item_pressed" android:toId="@+id/item_normal"> <animation-list android:id="@+id/selected"

android:oneshot="true"> <item android:drawable="@drawable/attack_magic1"

android:duration="100" /> <item android:drawable="@drawable/attack_magic2"

android:duration="100" /></animation-list></transition></animated-selector>

V21

Normal

Pressed

Normal

View state

Display

ClipDrawableRotateDrawableScaleDrawable

AnimationDrawableTransitionDrawableStateListDrawable

AnimatedStateListDrawable

AnimatedVectorDrawable

Think Drawables

Page 26: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

<?xml version="1.0" encoding="utf-8"?><vector android:viewportWidth="500" android:viewportHeight="500" android:width="500px" android:height="500px"> <!--Make group to animate them separately using ObjectAnimator--> <!--Define the pivot in the group they will be used by ObjectAnimator--> <group android:name="tete" android:pivotX="250.0" android:pivotY="100.0"> <path android:name="head" android:fillColor="#9FBF3B" android:pathData="..." /> </group>...</vector>

<?xml version="1.0" encoding="utf-8"?>

<animated-vector android:drawable="@drawable/my_svg" > <target android:name="tete" android:animation="@anim/anim_svg"

/></animated-vector>

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"> <!-- res/anim/rotation.xml --><objectAnimator android:duration="6000" android:propertyName="rotation" android:valueFrom="0" android:valueTo="360" />

</set>

drawable/my_svg drawable/my_svg_animated anim/anim_svg

use

use

layout/my_view

use

<ImageView android:id="@+id/imvAnimatedVector" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:src="@drawable/my_svg_animated"/>

use

animatedVectorDrawable.start();

V21

AnimatedVectorDrawable: Animate Shapes

TransitionDrawableStateListDrawable

AnimatedStateListDrawable

AnimatedVectorDrawable

Page 27: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

<?xml version="1.0" encoding="utf-8"?><vector android:viewportWidth="500" android:viewportHeight="500" android:width="500px" android:height="500px"> <!--Make group to animate them separately using ObjectAnimator--> <!--Define the pivot in the group they will be used by ObjectAnimator--> <group android:name="tete" android:pivotX="250.0" android:pivotY="100.0"> <path android:name="head" android:fillColor="#9FBF3B" android:pathData="..." /> </group>...</vector>

<?xml version="1.0" encoding="utf-8"?>

<animated-vector android:drawable="@drawable/my_svg" > <target android:name="tete" android:animation="@anim/animpath_svg"

/></animated-vector>

<?xml version="1.0" encoding="utf-8"?><set > <!-- res/anim/rotation.xml --> <objectAnimator android:duration="6000" android:propertyName="pathData" android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z" android:valueTo="M300,70 l 0,-70 70,0 0,140 -70,0 z" android:valueType="pathType"/>

</set>

drawable/my_svg drawable/my_svg_animated anim/animpath_svg

use

use

layout/my_view

use

<ImageView android:id="@+id/imvAnimatedVector2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:src="@drawable/my_svg_animated"/>

use

animatedVectorDrawable.start();

V21

AnimatedVectorDrawable: Morph Shapes

TransitionDrawableStateListDrawable

AnimatedStateListDrawable

AnimatedVectorDrawable

Page 28: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

The constraints that kill for path transformation: "Note that the paths must be compatible for morphing.

In more details, the paths should have exact same length of commands , and exact same length of

parameters for each commands."

It means: you won't use it expect for so simple trick (arrow to hamburger).=>Waiting for tools !

AnimatedVectorDrawable: Morph Shapes constraintV21

Page 29: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

And here it is !!!https://github.com/bonnyfone/vectalign

V21

AnimatedVectorDrawable: Morph Shapes tool

Page 30: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

To create Svg and/or simplify themhttps://inkscape.org/

To convert Svg into VectorDrawablehttp://inloop.github.io/svg2android/

A good practice :Define your path in a String file (res\values\my_path_string.xml)

V21

AnimatedVectorDrawable: others needed tools

But even with that it's the hell on earth=>working on a Github project

Page 31: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Others best friends

Animation is simple

Page 32: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Make it simple and magic: You can animate any view

translationX , translationY, rotationX, rotationY, rotation, scaleX, scaleY, pivotX,pivotY, x,y,alpha and more

with one line of code !

myView.animate().setDuration(300).x(20).rotationY(60).start();

V13

ViewPropertyAnimator

Page 33: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

myView.animate().rotation(360);is equivalent to

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f).start();

ViewPropertyAnimator is based on ObjectAnimatorV13

Page 34: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Makes animations simple, magic and generic

V13

ObjectAnimator Demystify

Page 35: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

First extends what you want (Object or View or what ever)

public class BlueDot extends View {

V13

ObjectAnimator Demystify

Page 36: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Define the property to animate using set/*MyProperty*/

public class BlueDot extends View {/** * The property to animate * * @param parameter value of the state to calculate the animation of the object */

private void setToto(int parameter) {/*Do your stuff, (call invalidate to redraw view)*/

V13

ObjectAnimator Demystify

Page 37: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Then animatepublic class BlueDot extends View {/** * The property to animate * @param parameter value of the state to calculate the animation of the object */private void setToto(int parameter) {/*Do your stuff,(call invalidate to redraw view)*/

ObjectAnimator.ofInt(blueDot, "toto", 0, 110) .start();

V13

ObjectAnimator Demystify

Page 38: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

ClipDrawable

Handler clipDrawableHandler=new Handler();Runnable clipDrawableRunnable=new Runnable() {

@Override public void run() {level++;

clipDrawableHorizontal.setLevel(level); clipDrawableHandler.postDelayed(clipDrawableRunnable,32); }};

<?xml version="1.0" encoding="utf-8"?><clip xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/ic_android2ee" android:clipOrientation="horizontal" android:gravity="left" />

It was before

Works with every think !V13

ObjectAnimator Demystify

Page 39: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Works with every think !

public class MyActivity extends Activity{

private void setMoveDrawable(int level){ clipDrawableHorizontal.setLevel(level); }

private void animateDrawable() { ObjectAnimator.ofInt(this, "MoveDrawable", 0, 10000).start();}

No more Handler neither Runnable !!!yes thanks Chet !

V13

ObjectAnimator Demystify

Page 40: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Scene Transition

Page 41: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Demonstration !

Scene and Transitionv16

Page 42: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

One xml line to add<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/llSceneRoot" android:animateLayoutChanges="true">

v16Scene and Transition

Page 43: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

One xml line to add<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/llSceneRoot" android:animateLayoutChanges="true">

One line of code to addif(postICS){ LayoutTransition transition = ((ViewGroup)findViewById(R.id.llSceneRoot)).getLayoutTransition(); // New capability as of Jellybean; monitor the container for *all* layout changes // (not just add/remove/visibility changes) and animate these changes as well.(==size) transition.enableTransitionType(LayoutTransition.CHANGING);}

v16Scene and Transition

Page 44: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

v16

Activities transitions

v8

Page 45: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

You have the choice between Custom animation

Intent slidingActivity = new Intent(this, SlidingActivity.class);ActivityCompat.startActivity(this, slidingActivity, translationBundle);}

v16Activities transitions

v8

Bundle translationBundle = ActivityOptionsCompat.makeCustomAnimation(this, R.anim.anim_push_left_in_a2ee,R.anim.anim_push_left_out_a2ee).toBundle();

Page 46: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

You have the choice between Custom animation

Scaling Component

Intent slidingActivity = new Intent(this, SlidingActivity.class);ActivityCompat.startActivity(this, slidingActivity, translationBundle);}

v16Activities transitions

v8

Bundle translationBundle = ActivityOptionsCompat.makeCustomAnimation(this, R.anim.anim_push_left_in_a2ee,R.anim.anim_push_left_out_a2ee).toBundle();

Bundle translationBundle = ActivityOptionsCompat.makeScaleUpAnimation(btnScaling,0,0,btnScaling.getWidth(),btnScaling.getHeight() ).toBundle();

Page 47: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

You have the choice between: Custom animation

Scaling Component

Scaling bitmap

Intent slidingActivity = new Intent(this, SlidingActivity.class);ActivityCompat.startActivity(this, slidingActivity, translationBundle);}

Bundle translationBundle = ActivityOptionsCompat.makeCustomAnimation(this, R.anim.anim_push_left_in_a2ee,R.anim.anim_push_left_out_a2ee).toBundle();

Bundle translationBundle = ActivityOptionsCompat.makeScaleUpAnimation(btnScaling,0,0,btnScaling.getWidth(),btnScaling.getHeight() ).toBundle();

Bundle translationBundle = ActivityOptionsCompat.makeThumbnailScaleUpAnimation(imvSmiley,bitmap,0,0).toBundle();

v16Activities transitions

v8

Page 48: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

You have the choice between: Custom animation

Scaling Component

Scaling bitmap

You need to reverse :

public class otherActivity extends Activity {public void finish() { super.finish(); //this work for all version superior to level 5 overridePendingTransition(R.anim.anim_push_right_in_a2ee, R.anim.anim_push_right_out_a2ee);}}

v16Activities transitions

v8

Page 49: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

AwesomeFirst manage your theme

<resources> <!-- Thanks to :--> <!-- http://code.tutsplus.com/tutorials/introduction-to-the-new-lollipop-activity-transitions&#45;&#45;cms-23711--> <!-- Base application theme. --> <style name="AppTheme" parent="BaseTheme"> <!-- Set the transition between activities effective --> <item name="android:windowContentTransitions">true</item>

<item name="android:windowEnterTransition">@android:transition/slide_bottom</item> <item name="android:windowExitTransition">@android:transition/slide_bottom</item>

<item name="android:windowAllowEnterTransitionOverlap">true</item> <item name="android:windowAllowReturnTransitionOverlap">true</item> <item name="android:windowSharedElementEnterTransition">@android:transition/move</item> <item name="android:windowSharedElementExitTransition">@android:transition/move</item>

</style></resources>

v21New Activities transitions

Page 50: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Set the android:transitionName to your components<ImageButton android:id="@+id/ibtnSprite" android:transitionName="@string/imvSprite_transition" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:layout_gravity="center" android:src="@drawable/attack_magic_animation" />

<ImageView android:id="@+id/imvSprite" android:transitionName="@string/imvSprite_transition" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@drawable/attack_magic_animation" />

layout/main_activity layout/other_activity

v21New Activities transitions

Page 51: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Make your pairs and launch the new Activity

if (isPostLollipop) { ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation( this, new Pair<View, String>(imvSprites, getString(R.string.imvSprite_transition)), ); }

ActivityCompat.startActivity(MainActivity.this, intent, options.toBundle());}

v21New Activities transitions

Page 52: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

The best for the end !

Page 53: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

53

RecyclerView

Page 54: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

54

BuildGradle: Add the library

dependencies { ... compile 'com.android.support:recyclerview-v7:23.0.1'

Page 55: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

55

Principle

RecyclerView

Adapter

ViewHolder

LayoutManager

ItemAnimator ItemDecoratorItemView management

(ClickListener,Animation...)

dataSet

Page 56: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

56

RecyclerView: codeIts the natural evolution of the ListView, the ViewHolder is the one responsible of the view management

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View myView=inflater.inflate(R.layout.recyclerview,container,false);

recyclerView= (RecyclerView) myView.findViewById(R.id.my_recycler_view);

// use a layout manager recyclerViewLayoutManager = getLayoutManager(); recyclerView.setLayoutManager(recyclerViewLayoutManager);

// specify an adapter (see also next example) recyclerViewAdapter = new RecyclerViewAdapter(humans,getActivity()); recyclerView.setAdapter(recyclerViewAdapter); return myView ;}

find the View

set the LayoutManager

set the Adapter

Same principles as for ListView

Page 57: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

57

RecyclerView: The AdapterCodeThis is the same code as for the ListView (ViewHolder next slide)

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>{

/****Attributes (t for temp)**/ private ArrayList<Human> humans; private LayoutInflater inflater; private View tNewView; private ViewHolder tViewHolder; private Human tHuman;

/****** Constructor**/ public RecyclerViewAdapter(ArrayList<Human> dataSet,Context ctx){ humans=dataSet; inflater=LayoutInflater.from(ctx); }

@Override public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { tNewView=inflater.inflate(R.layout.simple_item,parent,false); tViewHolder=new ViewHolder(tNewView); return tViewHolder; }

@Override public void onBindViewHolder(RecyclerViewAdapter.ViewHolder holder, int position) { tHuman=humans.get(position); holder.getTxvName().setText(tHuman.getName()); holder.getTxvFirstName().setText(tHuman.getFirstName()); holder.getTxvMessage().setText(tHuman.getMessage()); } @Override public int getItemCount() { return humans.size(); }

Page 58: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

58

RecyclerView: The AdapterCodeThis is the same code as for the ListView (ViewHolder next slide)

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>{

/****Attributes (t for temp)**/ private ArrayList<Human> humans; private LayoutInflater inflater; private View tNewView; private ViewHolder tViewHolder; private Human tHuman;

/****** Constructor**/ public RecyclerViewAdapter(ArrayList<Human> dataSet,Context ctx){ humans=dataSet; inflater=LayoutInflater.from(ctx); }

@Override public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { tNewView=inflater.inflate(R.layout.simple_item,parent,false); tViewHolder=new ViewHolder(tNewView); return tViewHolder; }

@Override public void onBindViewHolder(RecyclerViewAdapter.ViewHolder holder, int position) { tHuman=humans.get(position); holder.getTxvName().setText(tHuman.getName()); holder.getTxvFirstName().setText(tHuman.getFirstName()); holder.getTxvMessage().setText(tHuman.getMessage()); } @Override public int getItemCount() { return humans.size(); }

Inflate the view and its viewHolderReturn the ViewHolder

Update the View using the ViewHolder

Set your DataSet and your LayoutInflater

Page 59: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

59

RecyclerView: Le code de l'AdapterLe ViewHolder gère la vue qu'il encapsule

public class ViewHolder extends RecyclerView.ViewHolder{ TextView txvName=null; TextView txvFirstName=null; TextView txvMessage=null; View.OnClickListener clickListener; int position;

public ViewHolder(View itemView) { super(itemView); txvName= (TextView) itemView.findViewById(R.id.txvName); txvFirstName= (TextView) itemView.findViewById(R.id.txvFirstName); txvMessage= (TextView) itemView.findViewById(R.id.txvMessage); clickListener=new View.OnClickListener() { public void onClick(View v) {changeTxvMessageVisibilityState(); } }; itemView.setOnClickListener(clickListener); }

public TextView getTxvFirstName() {return txvFirstName;} public TextView getTxvMessage() {return txvMessage;} public TextView getTxvName() {return txvName;} public void changeTxvMessageVisibilityState(){ //Do the stuff }}

Page 60: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

60

RecyclerView: Les LayoutManagerLe LinearLayoutManager

public RecyclerView.LayoutManager getLayoutManager() { return new LinearLayoutManager(getContext());}

Page 61: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

61

RecyclerView: Les LayoutManagerLe StaggeredLayoutManager

public RecyclerView.LayoutManager getLayoutManager() {

StaggeredGridLayoutManager stagLayoutManager=new StaggeredGridLayoutManager(2,GridLayoutManager.VERTICAL);

stagLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);

return stagLayoutManager;}

Page 62: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

62

RecyclerView: Les LayoutManagerLe GridLayoutManager

public RecyclerView.LayoutManager getLayoutManager() {

GridLayoutManager gridLayoutManager=new GridLayoutManager(getContext(),2,GridLayoutManager.VERTICAL,false);

//define specific span of specific cells according to a rule gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int arg0) { return (arg0 % 3) == 0 ? 2 : 1; } }); return gridLayoutManager;}

Page 63: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

63

CoordinatorLayout

Tutoriaux:RecyclerView

Page 64: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

64

BuildGradle: Add the library

dependencies { ... compile 'com.android.support:design:23.0.1'

Page 65: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

65

All is done in the Layout file

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".CoordinatorLayout">

The parent Layout of all yours Layouts: The CoordinatorLayout

Page 66: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

66

Everything is done in the layout

<android.support.design.widget.CoordinatorLayout >

<android.support.design.widget.AppBarLayout ... android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

<android.support.v7.widget.Toolbar ... app:layout_scrollFlags="scroll|enterAlways"/>

<android.support.design.widget.TabLayout ... android:fillViewport="true"/>

</android.support.design.widget.AppBarLayout>

<android.support.v4.view.ViewPager //Your content ... app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</android.support.design.widget.CoordinatorLayout >

Page 67: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

67

Going further with the CollapsingToolBarLayout<android.support.design.widget.AppBarLayout ... > <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_scrollFlags="scroll|exitUntilCollapsed" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:expandedTitleMarginStart="48dp" app:expandedTitleMarginEnd="64dp">

<ImageView ... android:fitsSystemWindows="true" app:layout_collapseMode="parallax" />

<android.support.v7.widget.Toolbar ... app:layout_scrollFlags="scroll|enterAlways"/>

<android.support.design.widget.TabLayout ... android:fillViewport="true"/>

</android.support.design.widget.CollapsingToolbarLayout></android.support.design.widget.AppBarLayout>

Page 68: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

68

Plus complexe avec CollapsingToolBarLayout

<android.support.design.widget.AppBarLayout...>

<android.support.design.widget.CollapsingToolbarLayout...>

<ImageView.../>

<android.support.design.widget.TabLayout .../>

<android.support.v7.widget.Toolbar.../>

</android.support.design.widget.CollapsingToolbarLayout>

</android.support.design.widget.AppBarLayout>

Set the title of the ActionBar on the CollapsingToolbarLayout not

on the ToolBar!

Page 69: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

69

Plus complexe avec CollapsingToolBarLayout<android.support.design.widget.AppBarLayout...>

<android.support.design.widget.CollapsingToolbarLayout...>

<ImageView.../> <android.support.v7.widget.Toolbar.../>

<android.support.design.widget.TabLayout .../>

</android.support.design.widget.CollapsingToolbarLayout>

</android.support.design.widget.AppBarLayout>

switch

Page 70: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

71

The one I prefer

<android.support.design.widget.AppBarLayout ... >

<android.support.design.widget.CollapsingToolbarLayout ... >

<ImageView ... />

<android.support.v7.widget.Toolbar ... />

</android.support.design.widget.CollapsingToolbarLayout>

<android.support.design.widget.TabLayout />

</android.support.design.widget.AppBarLayout>

collapsingToolbar.setContentScrimResource(R.drawable.cardview_background_toolbar);

Page 71: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

An old trick : PageTransformer

Page 72: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

73

V13

ViewPager

Page 73: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Demonstration !

V13

ViewPager

Page 74: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

75

activity_main.xml<?xml version="1.0" encoding="utf-8"?>

<android.support.v4.view.ViewPager android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/viewpager" android:background="#FF00F0F0"></android.support.v4.view.ViewPager>

public class MainActivity extends ActionBarActivity { private MyPagerAdapter pagerAdapter; private ViewPager viewPager; @Override protected void onCreate(Bundle savedInstanceState) {... //instanciate the PageAdapter pagerAdapter=new MyPagerAdapter(this); //Find the viewPager viewPager = (ViewPager) super.findViewById(R.id.viewpager); // Affectation de l'adapter au ViewPager viewPager.setAdapter(pagerAdapter);

}

V13

ViewPager

Page 75: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

76

public class MyPagerAdapter extends FragmentPagerAdapter { private final ArrayList<Fragment> fragments;

public MyPagerAdapter(ActionBarActivity ctx) { super(ctx.getSupportFragmentManager()); fragments = new ArrayList<Fragment>(); //A stuff I never did before, instanciate my fragment Fragment frag =new MyFragment1(); fragments.add(frag);... }

public Fragment getItem(int position) { return fragments.get(position); }

public int getCount() {return fragments.size(); }

V13

ViewPager

Page 76: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

77

public class MainActivity extends ActionBarActivity {

@Overrideprotected void onCreate(Bundle savedInstanceState) {...//instanciate the PageAdapterpagerAdapter=new MyPagerAdapter(this);//Find the viewPagerviewPager = (ViewPager) super.findViewById(R.id.viewpager);// Affectation de l'adapter au ViewPagerviewPager.setAdapter(pagerAdapter);if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){ viewPager.setPageTransformer(true, new PageTransformer(this));}

V13

ViewPager

Page 77: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

78

public class MyPageTransformer implements ViewPager.PageTransformer{ RecyclerView myRecyclerView;

public void transformPage(View view, float position) { //Only the main layout is passed here/ myRecyclerView= (RecyclerView) view.findViewById(R.id.my_recycler_view); if (position < -1) { // [-Infinity,-1)This page is way off-screen to the left. view.setAlpha(0); }

else if (position < 1) { //in the visible range [-1,1] myRecyclerView.setAlpha(1-Math.abs(position)); view.setAlpha(1); if (position < 0) {//coming from left myRecyclerView.setRotationX((position * 360)); } else {//coming from right myRecyclerView.setRotationX(-1*position *360); } }

else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0); } }}

V13

ViewPager

Page 78: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Tips

Page 79: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

How to get the screen size ?@SuppressLint("NewApi")private void getViewSize() { //this is an usual trick when we want to know the dimension of our view //initialize dimensions of the view WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); if (postICS) { Point size = new Point(); display.getSize(size); width = size.x; height = size.y; } else { width = display.getWidth(); // deprecated height = display.getHeight(); // deprecated }}

V1

Get screen size

Page 80: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

When customizing you view, you have to overwrite the following method:

protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); this.w = w; this.h = h; centerX = w / 2; centerY = h / 2; //...}

V1

Get custom view size

Page 81: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Use the ViewTreeObserver

private void getEditButtonWidth() { //this is an usual trick when we want to know the dimension of the elements of our view //find the dimension of the EditButton ViewTreeObserver vto = btnEdit.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { btnEdit.getViewTreeObserver().removeGlobalOnLayoutListener(this); btnEditWidth = btnEdit.getMeasuredWidth(); } });}

V1

Get widget view size

Page 82: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Use the LayoutParameter of the ViewGroup

private void changeImvSprite1Size(){ //Change the LayoutParameter to change the size of view if(isImvSprite1Expended){ imvSprite1.setLayoutParams(imvSpritesLayoutParamNormal); }else{ imvSprite1.setLayoutParams(imvSpritesLayoutParamExpanded); } isImvSprite1Expended=!isImvSprite1Expended;}

private void initializeImvSpriteSize() { //get the real size of the components imvSprite1Height = imvSprite1.getMeasuredHeight(); //initialize the layout parameter for the normal size imvSpritesLayoutParamNormal = new LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, imvSprite1Height); //initialize the layout parameter for the expanded size imvSpritesLayoutParamExpanded= new LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, 2*imvSprite1Height);}

private LinearLayout.LayoutParams imvSpritesLayoutParamNormal, imvSpritesLayoutParamExpanded ;

V1

Change components size

Page 83: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Invalidate and dirtyArea or layoutRequest

V1

Redraw

Page 84: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Make your own paint : Paint dotPaint= new Paint(); //initialize the shader (stuff that make the color of the paint depending on // the location in the screen and a set of colors) //@chiuki at droidcon london int[] rainbow = getRainbowColors(); Shader shader = new LinearGradient(0, 0, 0, w, rainbow, null, Shader.TileMode.MIRROR); Matrix matrix = new Matrix(); matrix.setRotate(90); shader.setLocalMatrix(matrix); dotPaint.setShader(shader);

private int[] getRainbowColors() { return new int[]{ getResources().getColor(R.color.rainbow_red), getResources().getColor(R.color.rainbow_yellow), getResources().getColor(R.color.rainbow_green), getResources().getColor(R.color.rainbow_turquoise), getResources().getColor(R.color.rainbow_blue), getResources().getColor(R.color.rainbow_purple) };}

V1

Make rainbow paint

Page 85: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

First: Simplify your layout !!!if not enough you can also:

User LayerType Hardware accelerated

btnDoNotPress.setLayerType(View.LAYER_TYPE_HARDWARE,null);

new Animator.AnimatorListener() {public void onAnimationEnd(Animator animation) { btnDoNotPress.setLayerType(View.LAYER_TYPE_NONE, null);

}

V1

Optimize your Animation

Page 86: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

#[email protected]

www.android2ee.com

Android by passionPassionate by Training

Expert by technical love

Questions ?

Page 87: Animate Me! if you don't do it for me, do it for Chet - DroidconLondon2015

Code:https://github.com/MathiasSeguy-

Android2EE

Android2EE@android2ee

Thank you!

Mathias Seguy

Slides:http://fr.slideshare.net/Android2EE