Lock in $30 Savings on PRO—Offer Ends Soon! ⏳
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
実例で理解する Material Design Animation
Search
Ryo Sakaguchi
February 08, 2018
Programming
9
5.3k
実例で理解する Material Design Animation
DroidKaigi 2018 2/8 Room2
Ryo Sakaguchi
February 08, 2018
Tweet
Share
More Decks by Ryo Sakaguchi
See All by Ryo Sakaguchi
Android Architecture Componentsを使って、改善・効率化するAndroidアプリ開発
wakwak3125
0
1.3k
Test multiple APKs with Robolectric
wakwak3125
0
770
Clip, Elevation and ViewOutlineProvider
wakwak3125
1
1.3k
WebView as Fancy and effective View
wakwak3125
1
1.5k
ViewPager2をちょっとさわってみよう
wakwak3125
0
1.6k
年末だし、振り返るKotlin
wakwak3125
1
1.1k
社内ライブラリのアップデートフロー
wakwak3125
4
3.7k
Wantedly Peopleのリリースフロー
wakwak3125
1
4.6k
KOINかわいいよ、KOIN
wakwak3125
0
950
Other Decks in Programming
See All in Programming
30分でDoctrineの仕組みと使い方を完全にマスターする / phpconkagawa 2025 Doctrine
ttskch
3
730
CSC305 Lecture 17
javiergs
PRO
0
270
Herb to ReActionView: A New Foundation for the View Layer @ San Francisco Ruby Conference 2025
marcoroth
0
240
エディターってAIで操作できるんだぜ
kis9a
0
650
全員アーキテクトで挑む、 巨大で高密度なドメインの紐解き方
agatan
8
18k
20251127_ぼっちのための懇親会対策会議
kokamoto01_metaps
2
400
S3 VectorsとStrands Agentsを利用したAgentic RAGシステムの構築
tosuri13
5
260
レイトレZ世代に捧ぐ、今からレイトレを始めるための小径
ichi_raven
0
490
新卒エンジニアのプルリクエスト with AI駆動
fukunaga2025
0
140
AI時代もSEOを頑張っている話
shirahama_x
0
230
関数実行の裏側では何が起きているのか?
minop1205
1
560
ViewファーストなRailsアプリ開発のたのしさ
sugiwe
0
390
Featured
See All Featured
Testing 201, or: Great Expectations
jmmastey
46
7.8k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
196
69k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
54k
Designing for Performance
lara
610
69k
Fireside Chat
paigeccino
41
3.7k
Leading Effective Engineering Teams in the AI Era
addyosmani
8
1.2k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.3k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
Embracing the Ebb and Flow
colly
88
4.9k
Music & Morning Musume
bryan
46
7k
Agile that works and the tools we love
rasmusluckow
331
21k
Transcript
2018.2.8 ࣮ྫͰཧղ͢Δ Material Design Animation DroidKaigi 2018 Room2 Feb 8th,
2018 Ryo Sakaguchi (wakwak3125)
2018.2.8 Ryo Sakaguchi @wakwak3125 • Wantedly, Inc • Android application
developer • Wantedly People • Music, Guitar, UI/UX About me
2018.2.8 Ryo Sakaguchi @wakwak3125 • Wantedly, Inc • Android application
developer • Wantedly People • Music, Guitar, UI/UX About me
2018.2.8 Wantedly People
2018.2.8 Wantedly People • ໊ཧΞϓϦ • ػցֶशΛ༻͍ͯ͠Δ • ಡΈऔ໊ͬͨɺࣗͷใΛݩ ʹʮʯΛఏڙ͢Δ
• ؾ໊͍͍࣋ͪࡱӨମݧ
2018.2.8 Wantedly People • ໊ཧΞϓϦ • ػցֶशΛ༻͍ͯ͠Δ • ಡΈऔ໊ͬͨɺࣗͷใΛݩ ʹʮʯΛఏڙ͢Δ
• ؾ໊͍͍࣋ͪࡱӨମݧ
2018.2.8 Agenda
2018.2.8 Agenda • ʮʯػೳͷΞχϝʔγϣϯͷհ • ࣮ͷղઆ • Ξχϝʔγϣϯ࣮ͷצॴ • ΞχϝʔγϣϯͷDebug
2018.2.8 ʮʯػೳͷΞχϝʔγϣϯհ
2018.2.8 Article ͷهࣄΛදࣔ͢Δը໘ • ৴͞ΕΔΛදࣔ͢Δը໘ • Ϣʔβʔʹରͯͯ͠͠΄͍͠ʮը૾ʯ Λ࣠ʹΞχϝʔγϣϯ͢Δɻ • RecyclerViewʹΧʔυܕͷΞΠςϜΛฒ
ɺͦΕ͕Expand͢ΔΠϝʔδ • ΧʔυഎܠˠΧόʔΠϝʔδ • هࣄͷ֓ཁ/λΠτϧͷίϯςΩετ Λڞ༗Ͱ͖Δ ʮʯػೳͷΞχϝʔγϣϯհ Article
2018.2.8 Graphic contents ΠϯϑΥάϥϑΟοΫ • ΠϯϑΥάϥϑΟοΫ͕ϝΠϯͷهࣄΛ දࣔ͢Δ • ίϯςϯπࣗମAfterEffectsΛ༻͠ ͯ࡞͠ɺbodymovinΛ༻ͯ͠
WebViewͰ࠶ੜ͍ͯ͠Δ • Χʔυͷഎܠը૾͕શ໘ʹ͕͍ͬͯ͘ • ΧʔυˠهࣄৄࡉͷભҠͰੈք؍ ΛଛͳΘͳ͍ ʮʯػೳͷΞχϝʔγϣϯհ Graphic contents
2018.2.8 Timeline هࣄ͕දࣔ͞ΕΔTimeline • هࣄΛҰཡͰදࣔ͢ΔRecyclerView • Χʔυ͕എܠը૾Λ࣋ͭλΠϓͱ࣋ͨ ͳ͍λΠϓ͕͋Δ • എܠը૾Λ࣋ͭλΠϓͷͷͷ߹ɺ
Timelineͷഎܠશମʹϒϥʔ͕͔͔ͬ ͨͷ͕هࣄͷग़ݱͱڞʹΫϩεϑΣʔ υ͢Δ • ࠓճϝΠϯͰΛ͢ΔͭΓͷɺ SharedElementTransitionͱҧ͏͚ ͲɺҰԠհ ʮʯػೳͷΞχϝʔγϣϯհ Timeline
2018.2.8 ΞχϝʔγϣϯͬͯͳΜͰඞཁͳͷʁ
2018.2.8 ͔͍͍͔ͬ͜Β
2018.2.8 ͔͍͍͔ͬ͜Βʁ ͚ͩ͡Όͳ͍Ͱ͢ • ΞχϝʔγϣϯʹΑͬͯɺϢʔβʔʹ ͯ͠΄͍͠ͷΛΞϐʔϧͰ͖Δ • ͍ͬͯͯɺಥવίϯςϯπ͕ೖΕସ Θͬͨ෩ʹײͯ͡͠·͏Ϣʔβʔډ Δͣɻ
• Βͳ͍ΑΓͬͨ΄͏͕ઈରྑ͍ • Γ͗͢ྑ͘ͳ͍ɻ͚Ͳɺ·ͣ ࡞͔ͬͯΒ͍ͬͯ͘ͷ͕େࣄ • ͪΖΜ͔͍͍ͬͬͯ͜ͷ͋Δʂ ΞχϝʔγϣϯͬͯͳΜͰඞཁͳͷʁ
2018.2.8 ࣮ͷղઆ
2018.2.8 ࣮ͷղઆ • Shared Element Transitionͷجຊͷ ͓͞Β͍ • ֤ػೳ(Article/Graphic contents)
ʹґଘ͠ͳ͍෦ͷڞ௨࣮ͷ • ֤ػೳຖʹߦ͍ͬͯΔಛผͳ෦ͷ • Article • Graphic content
2018.2.8 ·ͣجຊͷ͓͞Β͍
2018.2.8 Transition Name 1/3 ڞ༗͍ͨ͠Viewʹ໊લΛ͚ͭΔ ·ͣجຊͷ͓͞Β͍ Shared Element Transition public
class MainActivity extends AppCompatActivity { ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView( this, R.layout.activity_main ); binding.button.setOnClickListener(v -> goToNextActivity()); } void goToNextActivity() { Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation( this, /*ભҠݩͷActivity*/ binding.imageView, /*ભҠݩͱભҠઌͰڞ༗͍ͨ͠View*/
2018.2.8 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding =
DataBindingUtil.setContentView( this, R.layout.activity_main ); binding.button.setOnClickListener(v -> goToNextActivity()); } Transition Name 2/3 TransitionʹඞཁͳใΛBundleʹ٧Ίͯ͢ ·ͣجຊͷ͓͞Β͍ Shared Element Transition void goToNextActivity() { Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation( this, /*ભҠݩͷActivity*/ binding.imageView, /*ભҠݩͱભҠઌͰڞ༗͍ͨ͠View*/ "transition:image" /*ڞ༗͍ͨ͠ViewͷTransition Name*/ ).toBundle(); ActivityCompat.startActivity( this, new Intent(this, NextActivity.class), bundle); }
2018.2.8 Transition Name 3/3 ભҠઌͷActivityͷڞ༗͍ͨ͠ViewʹTransition NameΛηοτ͢Δ ·ͣجຊͷ͓͞Β͍ Shared Element Transition
this, /*ભҠݩͷActivity*/ binding.imageView, /*ભҠݩͱભҠઌͰڞ༗͍ͨ͠View*/ "transition:image" /*ڞ༗͍ͨ͠ViewͷTransition Name*/ ).toBundle(); ActivityCompat.startActivity( this, new Intent(this, NextActivity.class), bundle); } public class NextActivity extends AppCompatActivity { ActivityNextBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_next); binding.imageView.setTransitionName("transition:image"); } }
2018.2.8
2018.2.8 Default animation theme_material.xmlͰ σϑΥϧτͰҎԼͷΞχϝʔγϣϯ͕ηοτ͞Ε͍ͯΔ ·ͣجຊͷ͓͞Β͍ Shared Element Transition <transitionSet
xmlns:android="http://schemas.android.com/apk/res/android"> <changeBounds/> <changeTransform/> <changeClipBounds/> <changeImageTransform/> </transitionSet> move.xml
2018.2.8 Postpone Transition Transition animationΛҙͷλΠϛϯάͰ։࢝Ͱ͖Δ ·ͣجຊͷ͓͞Β͍ Shared Element Transition public
class NextActivity extends AppCompatActivity { static final Handler sHandler = new Handler(Looper.getMainLooper()); ActivityNextBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_next); binding.imageView.setTransitionName("transition:image"); ActivityCompat.postponeEnterTransition(this); sHandler.postDelayed(() -> ActivityCompat.startPostponedEnterTransition(this), 1000 ); } }
2018.2.8 ࣮ͷղઆ Wantedly PeopleͰ͍ͬͯΔShared Element Transitionͷڞ௨ͳ෦
2018.2.8 ࣮ͷղઆ ڞ௨ͷ෦ .BJO"DUJWJUZ
2018.2.8 ࣮ͷղઆ ڞ௨ͷ෦ .BJO"DUJWJUZ 5JNFMJOF'SBHNFOU
2018.2.8 ࣮ͷղઆ ڞ௨ͷ෦ .BJO"DUJWJUZ 5JNFMJOF'SBHNFOU 1PTU"SUJDMF"DUJWJZ
2018.2.8 ࣮ͷղઆ ڞ௨ͷ෦ .BJO"DUJWJUZ 5JNFMJOF'SBHNFOU 1PTU"SUJDMF"DUJWJZ 1PTU"SUJDMF'SBHNFOU
2018.2.8 ࣮ͷղઆ ڞ௨ͷ෦ .BJO"DUJWJUZ 5JNFMJOF'SBHNFOU 1PTU"SUJDMF"DUJWJZ 1PTU"SUJDMF'SBHNFOU
2018.2.8 ͔͜͜ΒϓϩμΫγϣϯίʔυ ͍Ζ͍Ζͳྺ࢙తͳഎܠͰग़དྷ্͕ͬͯ·͢ɻ ࠓେʹݟͯ΄͍͠ʂ Page Title Page Subtitle
2018.2.8 TimelineFragment ͜ͷFragment͔ΒTransitionΛ։࢝͢Δ /** * @param fragment ભҠݩͷFragment * @param
postKey هࣄͷKey * @param provider TransitionʹඞཁͳViewΛViewHolder͔Βऔͬͯ͘Δ * adapterΛ࣋ͭ */ public void openPost(BaseFragment fragment, String postKey, PostLogic.ITransitionAdapterProvider provider) { PostArticleFragment nextFragment = PostArticleFragment.newInstance(postKey); TransitionExtra extra = new TransitionExtra.Builder().build(); ࣮ͷղઆ ڞ௨ͷ෦ // ରͱͳΔViewͱTransition nameͷPairͷListΛ࡞Δ List<Pair<View, String>> pairList = new ArrayList<>(); if (provider != null) { PostLogic.TransitionAdapter adapter = provider.getTransitionAdapter(); // Viewʹରͯ͠ Transition nameΛ༩͍͑ͯ͘
2018.2.8 TimelineFragment ͜ͷFragment͔ΒTransitionΛ։࢝͢Δ * @param provider TransitionʹඞཁͳViewΛViewHolder͔Βऔͬͯ͘Δ * adapterΛ࣋ͭ */
public void openPost(BaseFragment fragment, String postKey, PostLogic.ITransitionAdapterProvider provider) { PostArticleFragment nextFragment = PostArticleFragment.newInstance(postKey); TransitionExtra extra = new TransitionExtra.Builder().build(); ࣮ͷղઆ ڞ௨ͷ෦ // ରͱͳΔViewͱTransition nameͷPairͷListΛ࡞Δ List<Pair<View, String>> pairList = new ArrayList<>(); if (provider != null) { PostLogic.TransitionAdapter adapter = provider.getTransitionAdapter(); // Viewʹରͯ͠ Transition nameΛ༩͍͑ͯ͘ pairList.add(Pair.create( adapter.getCoverImage(), fragment.getString(R.string.transition_image_cover))); // ଞʹView͕͋Ε͜͜Ͱηοτ͍ͯ͘͠... } //TransitionExtraʹpairListΛ͢ extra.setSharedElementPair(pairList); // BaseFragment͕ը໘ભҠΛߦ͏ؔΛ͍࣋ͬͯΔͷͰͦΕΛݺͼग़͢ fragment.replaceFragment(nextFragment, extra);
2018.2.8 BaseFragment replaceFragment ࣮ͷղઆ ڞ௨ͷ෦ public void replaceFragment(@NonNull BaseFragment fragment,
@Nullable TransitionExtra extra) { // BaseActivity͕listenerΛ࣮͍ͯ͠ΔͷͦͪΒʹϦϨʔ͢Δ getListener().replaceFragment(fragment, extra); }
2018.2.8 BaseActivity replaceFragment ࣮ͷղઆ ڞ௨ͷ෦ @Override public void replaceFragment(BaseFragment fragment,
@Nullable TransitionExtra extra) { if (extra != null) { Intent intent = PostArticleActivity.createIntent(this); Pair<View, String>[] sharedElements; if (!isEmpty(extra.getSharedElementPair())) { sharedElements = new Pair[extra.getSharedElementPair().size()]; for (int i = 0; i < extra.getSharedElementPair().size(); i++) { Pair<View, String> pair = extra.getSharedElementPair().get(i); if (pair.first != null && pair.second != null) { sharedElements[i] = pair; } } } else { sharedElements = new Pair[0]; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { ActivityOptionsCompat options =
2018.2.8 BaseActivity replaceFragment ࣮ͷղઆ ڞ௨ͷ෦ new Pair[extra.getSharedElementPair().size()]; for (int i
= 0; i < extra.getSharedElementPair().size(); i++) { Pair<View, String> pair = extra.getSharedElementPair().get(i); if (pair.first != null && pair.second != null) { sharedElements[i] = pair; } } } else { sharedElements = new Pair[0]; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(this, sharedElements); ActivityCompat.startActivity(this, intent, options.toBundle()); } else { startActivity(intent); } } else { /*͔͜͜ΒFragmentͰ։͘߹ͷॲཧ*/ }
2018.2.8 PostArticleActivity TransitionΛҰ࣌ఀࢭ͢Δ ࣮ͷղઆ ڞ௨ͷ෦ @Override protected void onCreate(Bundle savedInstanceState)
{ // ৭ʑͳॳظԽͷॲཧΛ͢Δ // FragmentͷView͕ग़དྷ্͕Δ·ͰɺTransitionΛҰ࣌ఀࢭ͢Δ // ࠶։Fragmentଆ͔ΒݺΜͰ͋͛Δ supportPostponeEnterTransition(); }
2018.2.8 PostArticleActivity ҎԼͷTransitionSet͕ద༻͞Ε͍ͯΔ <transitionSet xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:duration="250" android:transitionOrdering="together"> <changeBounds android:interpolator="@anim/interpolator_transition"
/> <changeTransform android:interpolator="@anim/interpolator_transition" /> <changeClipBounds android:interpolator="@anim/interpolator_transition" /> </transitionSet> ࣮ͷղઆ ڞ௨ͷ෦
2018.2.8 ࣮ͷղઆ Article
2018.2.8 Article Transition։࢝લ ࣮ͷղઆ Article • CardView • ImageView(Mark Zuckerberg)
• ߘऀΛදࣔ͢ΔϨΠΞτ • Title • ͍͍ͶίϝϯτϘλϯͷϨΠΞτ
2018.2.8 Article Transition։࢝લ ࣮ͷղઆ Article • CardView • ImageView(Mark Zuckerberg)
• ߘऀΛදࣔ͢ΔϨΠΞτ • Title • ͍͍ͶίϝϯτϘλϯͷϨΠΞτ
2018.2.8 Article Transition։࢝લ ࣮ͷղઆ Article • CardView • ImageView(Mark Zuckerberg)
• ߘऀΛදࣔ͢ΔϨΠΞτ • Title • ͍͍ͶίϝϯτϘλϯͷϨΠΞτ
2018.2.8 Article Transition։࢝લ ࣮ͷղઆ Article • CardView • ImageView(Mark Zuckerberg)
• ߘऀΛදࣔ͢ΔϨΠΞτ • Title • ͍͍ͶίϝϯτϘλϯͷϨΠΞτ
2018.2.8 Article Transition։࢝લ ࣮ͷղઆ Article • CardView • ImageView(Mark Zuckerberg)
• ߘऀΛදࣔ͢ΔϨΠΞτ • Title • ͍͍ͶίϝϯτϘλϯͷϨΠΞτ
2018.2.8 Article Transition։࢝ޙং൫ ࣮ͷղઆ Article • CardView • ImageView(Mark Zuckerberg)
• ߘऀΛදࣔ͢ΔϨΠΞτ • Title • ͍͍ͶίϝϯτϘλϯͷϨΠΞτ • CardViewͷSharedElementͱͯ͠ ஔ͍ͯͨ͠ന͍͚ͩͷ FrameLayout
2018.2.8 Article Transition։࢝ޙऴ൫ ࣮ͷղઆ Article • CardView • ImageView(Mark Zuckerberg)
• ߘऀΛදࣔ͢ΔϨΠΞτ • Title • ͍͍ͶίϝϯτϘλϯͷϨΠΞτ • CardViewͷSharedElementͱͯ͠ ஔ͍ͯͨ͠ന͍͚ͩͷ FrameLayout
2018.2.8
2018.2.8 Article Shared Elements ࣮ͷղઆ Article 5JNFMJOF'SBNFOU 1PTU"SUJDMF'SBHNFOU 7JFX %FTDSJQUJPO
7JFX %FTDSJQUJPO *NBHF7JFX Χʔυഎܠ *NBHF7JFX ΧόʔΠϝʔδ $BSE7JFX Χʔυ 'SBNF-BZPVU μϛʔͷഎܠ -JOFBS-BZPVU ߘऀͷϨΠΞτ -JOFBS-BZPVU ߘऀͷϨΠΞτ 5FYU7JFX λΠτϧ 5FYU7JFX λΠτϧ 5FYU7JFX ϝσΟΞ 5FYU7JFX ϝσΟΞ $POTUSBJOU-BZPVU ίϝϯτϘλϯͳͲ $POTUSBJOU-BZPVU ίϝϯτϘλϯͳͲ
2018.2.8 PostArticleFragment ϨΠΞτߏ <FrameLayout android:id="@+id/content_root"> ࣮ͷղઆ Article fragment_post_article.xml </FrameLayout> <android.support.constraint.ConstraintLayout
android:id=“@+id/reaction"> <!--͍͍ͶͷϘλϯͱ͔ίϝϯτͷϘλϯͱ͔--> </android.support.constraint.ConstraintLayout>
2018.2.8 <FrameLayout android:id="@+id/content_root"> ࣮ͷղઆ Article <FrameLayout android:id="@+id/background_view" android:background="@drawable/background_post_article" /> </FrameLayout>
<android.support.constraint.ConstraintLayout android:id=“@+id/reaction"> <!--͍͍ͶͷϘλϯͱ͔ίϝϯτͷϘλϯͱ͔--> </android.support.constraint.ConstraintLayout> PostArticleFragment ϨΠΞτߏ fragment_post_article.xml
2018.2.8 <FrameLayout android:id="@+id/content_root"> ࣮ͷղઆ Article <FrameLayout android:id="@+id/background_view" android:background="@drawable/background_post_article" /> <android.support.constraint.ConstraintLayout>
<android.support.v4.widget.NestedScrollView android:id="@+id/parent_nested_scroll_view"> </android.support.v4.widget.NestedScrollView> </FrameLayout> <android.support.constraint.ConstraintLayout android:id=“@+id/reaction"> <!--͍͍ͶͷϘλϯͱ͔ίϝϯτͷϘλϯͱ͔--> </android.support.constraint.ConstraintLayout> PostArticleFragment ϨΠΞτߏ fragment_post_article.xml
2018.2.8 <FrameLayout android:id="@+id/content_root"> ࣮ͷղઆ Article <FrameLayout android:id="@+id/background_view" android:background="@drawable/background_post_article" /> <FrameLayout
android:id="@+id/card"> <android.support.constraint.ConstraintLayout> <android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout> <android.support.v4.widget.NestedScrollView android:id="@+id/parent_nested_scroll_view"> </android.support.v4.widget.NestedScrollView> </FrameLayout> <android.support.constraint.ConstraintLayout android:id=“@+id/reaction"> <!--͍͍ͶͷϘλϯͱ͔ίϝϯτͷϘλϯͱ͔--> </android.support.constraint.ConstraintLayout> PostArticleFragment ϨΠΞτߏ fragment_post_article.xml
2018.2.8 <FrameLayout android:id="@+id/content_root"> ࣮ͷղઆ Article <FrameLayout android:id="@+id/background_view" android:background="@drawable/background_post_article" /> <FrameLayout
android:id="@+id/card"> <android.support.constraint.ConstraintLayout> <android.support.v4.widget.NestedScrollView android:id="@+id/parent_nested_scroll_view"> <FrameLayout android:id="@+id/card"> <ImageView android:id="@+id/image_cover" /> <android.support.constraint.ConstraintLayout> <include android:id="@+id/layout_poster" layout="@layout/item_post_user" /> <TextView android:id="@+id/text_title" /> <TextView android:id="@+id/label_ad" /> <TextView android:id="@+id/text_source_media" /> <TextView android:id="@+id/text_published_at" /> </android.support.constraint.ConstraintLayout> </FrameLayout> PostArticleFragment ϨΠΞτߏ fragment_post_article.xml
2018.2.8 ࣮ͷղઆ Article layout="@layout/item_post_user" /> <TextView android:id="@+id/text_title" /> <TextView android:id="@+id/label_ad"
/> <TextView android:id="@+id/text_source_media" /> <TextView android:id="@+id/text_published_at" /> </android.support.constraint.ConstraintLayout> </FrameLayout> <WebView android:id="@+id/web_view_short_article" /> <android.support.constraint.ConstraintLayout> </android.support.v4.widget.NestedScrollView> <android.support.constraint.ConstraintLayout android:id=“@+id/reaction"> <!--͍͍ͶͷϘλϯͱ͔ίϝϯτͷϘλϯͱ͔--> </android.support.constraint.ConstraintLayout> </FrameLayout> PostArticleFragment ϨΠΞτߏ fragment_post_article.xml
2018.2.8 @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup
container, @Nullable Bundle savedInstanceState) { mBinding = FragmentPostArticleBinding.inflate(inflater, container, false); ViewCompat.setTransitionName(mBinding.imageCover, getString(R.string.transition_image_cover)); ViewCompat.setTransitionName(mBinding.backgroundView, getString(R.string.transition_background)); ViewCompat.setTransitionName(mBinding.layoutPoster.getRoot(), getString(R.string.transition_item_user)); ViewCompat.setTransitionName(mBinding.textTitle, getString(R.string.transition_text_title)); ViewCompat.setTransitionName(mBinding.textSourceMedia, getString(R.string.transition_item_source_media)); ViewCompat.setTransitionName(mBinding.reaction, getString(R.string.transition_item_reactions)); return mBinding.getRoot(); } ࣮ͷղઆ Article PostArticleFragment TransitionपΓͷίʔυ
2018.2.8 @Override public void onStart() { super.onStart(); mPostAccessor.getObservable() .compose(this.bindToLifecycle()) .subscribe(post
-> { refreshPost(post, mState); getActivity().supportStartPostponedEnterTransition(); }, e -> recordError(null, this, e, null)); } ࣮ͷղઆ Article PostArticleFragment Ωϟογϡʹ͋Δهࣄͷσʔλ(post)Λऔಘ͠ɺྃޙTransitionΛ࠶։
2018.2.8 ϙΠϯτ • Transition։࢝લͷλΠϛϯάͰҰ࣌ఀࢭ͢Δ • Viewͷ४උ͕Ͱ͖ͨΒ࠶։ • Χʔυ͕expand͢ΔΑ͏ͳΞχϝʔγϣϯ ͪΐͬͱͨ͠τϦοΫΛ͍ͬͯΔ͚ͩɻ ͘͠ͳ͍
࣮ͷղઆ Article PostArticleFragment
2018.2.8 ࣮ͷղઆ Graphic contents
2018.2.8 Graphic contents Transition։࢝લ ࣮ͷղઆ Graphic contents • CardView •
ImageView(Χʔυഎܠ) • ߘऀΛදࣔ͢ΔϨΠΞτ • Title
2018.2.8 Graphic contents ࣮ͷղઆ Graphic contents • CardView • ImageView(Χʔυഎܠ)
• ߘऀΛදࣔ͢ΔϨΠΞτ • Title Transition։࢝લ
2018.2.8 Graphic contents ࣮ͷղઆ Graphic contents Transition։࢝લ • CardView •
ImageView(Χʔυഎܠ) • ߘऀΛදࣔ͢ΔϨΠΞτ • Title
2018.2.8 Graphic contents ࣮ͷղઆ Graphic contents Transition։࢝લ • CardView •
ImageView(Χʔυഎܠ) • ߘऀΛදࣔ͢ΔϨΠΞτ • Title
2018.2.8 Graphic contents Transition։࢝ޙং൫ • Χʔυશମ͕ը໘ΛຒΊΔ༻ʹ͕ͬͯ ͍͘ • ߘऀλΠτϧͳͲಉ͡Α͏ʹಈ͍ ͍ͯ͘
࣮ͷղઆ Graphic contents
2018.2.8 Graphic contents Transition։࢝ޙத൫ • എܠʹઃఆ͍ͯͨ͠ImageView͕ը໘ ͍ͬͺ͍ʹ͕Δ ࣮ͷղઆ Graphic contents
2018.2.8 Graphic contents Transition։࢝ޙऴ൫1/2 • ίϯςϯπͷϩʔυ͕ऴྃ͠ɺϔομʔ ෦͕ϑΣʔυΞτ&্ʹফ͍͑ͯ͘ ࣮ͷղઆ Graphic contents
2018.2.8 Graphic contents Transition։࢝ޙऴ൫2/2 • ίϯςϯπͱഎܠը૾͕ΫϩεϑΣʔυ ͢ΔܗͰೖΕସΘΔ ࣮ͷղઆ Graphic contents
2018.2.8
2018.2.8 Graphic contents Shared Elements ࣮ͷղઆ 5JNFMJOF'SBNFOU (SBQIJD$POUFOUT'SBHNFOU 7JFX %FTDSJQUJPO
7JFX %FTDSJQUJPO *NBHF7JFX Χʔυഎܠ *NBHF7JFX എܠը૾ -JOFBS-BZPVU ߘऀͷϨΠΞτ -JOFBS-BZPVU ߘऀͷϨΠΞτ 5FYU7JFX λΠτϧ 5FYU7JFX λΠτϧ 5FYU7JFX ϝσΟΞ 5FYU7JFX ϝσΟΞ Graphic contents
2018.2.8 GraphicContentsFragment ϨΠΞτߏ <android.support.constraint.ConstraintLayout android:id="@+id/content_root"> ࣮ͷղઆ fragment_graphic_contents.xml </android.support.constraint.ConstraintLayout> Graphic contents
2018.2.8 GraphicContentsFragment ϨΠΞτߏ <android.support.constraint.ConstraintLayout android:id="@+id/content_root"> ࣮ͷղઆ fragment_graphic_contents.xml </android.support.constraint.ConstraintLayout> Graphic contents
<WebView android:id="@+id/web_view_graphic_content" /> <ImageView android:id="@+id/background_view" />
2018.2.8 GraphicContentsFragment ϨΠΞτߏ <android.support.constraint.ConstraintLayout android:id="@+id/content_root"> ࣮ͷղઆ fragment_graphic_contents.xml </android.support.constraint.ConstraintLayout> Graphic contents
<WebView android:id="@+id/web_view_graphic_content" /> <ImageView android:id="@+id/background_view" />
2018.2.8 GraphicContentsFragment ϨΠΞτߏ <android.support.constraint.ConstraintLayout android:id="@+id/content_root"> ࣮ͷղઆ fragment_graphic_contents.xml </android.support.constraint.ConstraintLayout> Graphic contents
<WebView android:id="@+id/web_view_graphic_content" /> <ImageView android:id="@+id/background_view" /> <android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
2018.2.8 GraphicContentsFragment ϨΠΞτߏ <android.support.constraint.ConstraintLayout android:id="@+id/content_root"> ࣮ͷղઆ fragment_graphic_contents.xml </android.support.constraint.ConstraintLayout> Graphic contents
<WebView android:id="@+id/web_view_graphic_content" /> <ImageView android:id="@+id/background_view" /> <android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout> <FrameLayout android:id="@+id/header"> </FrameLayout>
2018.2.8 GraphicContentsFragment ϨΠΞτߏ <android.support.constraint.ConstraintLayout android:id="@+id/content_root"> ࣮ͷղઆ fragment_graphic_contents.xml Graphic contents <WebView
android:id="@+id/web_view_graphic_content" /> <ImageView android:id="@+id/background_view" /> <android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout> <FrameLayout android:id="@+id/header"> </FrameLayout> <android.support.constraint.ConstraintLayout> <include android:id="@+id/layout_poster" /> <TextView android:id="@+id/text_title" /> <TextView android:id="@+id/label_ad" /> <TextView android:id="@+id/text_source_media" /> <TextView android:id="@+id/text_published_at" /> </android.support.constraint.ConstraintLayout>
2018.2.8 GraphicContentsFragment TransitionपΓͷίʔυ1/2 ࣮ͷղઆ Graphic contents @Nullable @Override public View
onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { mBinding = FragmentPostArticleSp1Rev2Binding.inflate(inflater, container, false); ViewCompat.setTransitionName(mBinding.backgroundView, getString(R.string.transition_background)); ViewCompat.setTransitionName(mBinding.textTitle, getString(R.string.transition_text_title)); ViewCompat.setTransitionName(mBinding.layoutPoster.getRoot(), getString(R.string.transition_item_user)); ViewCompat.setTransitionName(mBinding.textSourceMedia, getString(R.string.transition_item_source_media)); return mBinding.getRoot(); }
2018.2.8 GraphicContentsFragment TransitionपΓͷίʔυ2/2 ࣮ͷղઆ Graphic contents @Override public void onPageFinished(WebView
view, String url) { super.onPageFinished(view, url); TransitionSet transitionSet = new TransitionSet().setDuration(400).setStartDelay(200); Fade fadeTransition = new Fade(); Transition slideUpTransition = new Slide(Gravity.TOP) .setStartDelay(100) .excludeTarget(R.id.background_view, true); transitionSet.addTransition(fadeTransition); transitionSet.addTransition(slideUpTransition); transitionSet.setInterpolator(AnimationUtils.loadInterpolator( getContext(), R.anim.accelerate_quad)); TransitionManager.beginDelayedTransition(((ViewGroup) getView()), transitionSet); mBinding.card.setVisibility(View.INVISIBLE); mBinding.backgroundView.setVisibility(View.INVISIBLE); view.setVisibility(View.VISIBLE); }
2018.2.8 @Override public void onStart() { super.onStart(); mPostAccessor.getObservable() .compose(this.bindToLifecycle()) .subscribe(post
-> { refreshPost(post, mState); getActivity().supportStartPostponedEnterTransition(); }, e -> recordError(null, this, e, null)); } ࣮ͷղઆ GraphicContentsFragment Ωϟογϡʹ͋Δهࣄͷσʔλ(post)Λऔಘ͠ɺྃޙTransitionΛ࠶։ Graphic contents
2018.2.8 ϙΠϯτ • Transition։࢝લͷλΠϛϯάͰҰ࣌ఀࢭ͢Δ • Viewͷ४උ͕Ͱ͖ͨΒ࠶։ • ࣮ࡍʹେ͖͘ಈ͍͍ͯΔͷImageView͚ͩ • ࡉ͔͘ಈ͍͍ͯΔΞΠςϜୡ
TransitionFrameworkͷ͓͔͛ • ΞχϝʔγϣϯͷAPI৭ʑ͋ΔͷͰɺཁॴཁ ॴͰΈ߹Θ͍ͯͬͯ͘͠ ࣮ͷղઆ GraphicContentsFragment Graphic contents
2018.2.8 Ξχϝʔγϣϯ࣮ͷצॴ ·ͣਅ͔ͬΒߟ͑ͣʹΖ͏
2018.2.8 ࡶʹ࡞Δ Ξχϝʔγϣϯ࣮ͷצॴ ·ͣਅ͔ͬΒߟ͑ͣʹΖ͏
2018.2.8 ὃ͢Α͏ʹߟ͑Δ Ξχϝʔγϣϯ࣮ͷצॴ ·ͣਅ͔ͬΒߟ͑ͣʹΖ͏
2018.2.8 ਅࣅΛ͢Δ Ξχϝʔγϣϯ࣮ͷצॴ ·ͣਅ͔ͬΒߟ͑ͣʹΖ͏
2018.2.8 ఘΊͳ͍ Ξχϝʔγϣϯ࣮ͷצॴ ·ͣਅ͔ͬΒߟ͑ͣʹΖ͏
2018.2.8 ΞχϝʔγϣϯͷDebug
2018.2.8 • AnimatorεέʔϧΛ5xʙ10xʹ͢Δ • ϨΠΞτͷڥքઢΛදࣔ͢Δ • γϣʔτΧοτͱͯ͠௨ͷॴʹஔ͍ͱ͘ ͱྑ͍͔ ΞχϝʔγϣϯͷDebug ։ൃऀΦϓγϣϯ
2018.2.8 • android:animateLayoutChanges=“true" ͕ViewGroupʹઃఆ͞Ε͍ͯΔ͔ʁ • ࣗͰద༻ͨ͠ΞχϝʔγϣϯͱίϯϑϦ ΫτΛى͍ͯ͜͠ΔՄೳੑ͕͋Δ • clipChildren/clipToPaddingͷࢦఆΛ͍ͬ͡ ͯΈΔ
• େ͖͘Λ͑ͯΞχϝʔγϣϯ͢Δ࣌ ্هͷࢦఆ͕ฉ͍ͯ͘Δɻfalseʹ͢Δ͜ͱ ͰViewGroupͷΛඈͼग़ͯ͠ಈ͘Α͏ ʹͰ͖Δ͔͠Εͳ͍ ΞχϝʔγϣϯͷDebug มͳಈ͖Λ͍ͯͨ͠Β1/2 ҎԼͷ߲ΛٙͬͯΈ͍͍͔ͯ
2018.2.8 • Ұ୴ϨΠΞτϑΝΠϧΛ࡞Γͯ͠ΈΔ • ແཧͷ͋ΔϨΠΞτϑΝΠϧʹͳ͍ͬͯ Δ͔͠Εͳ͍ • ֊͕ਂ͍ͱ͘͜͠ͳΔɻͳΔ͘ ConstrainLayoutͳͲΛͬͯ֊Λઙ͘ ͢Δ͜ͱ͕ग़དྷͳ͍͔ߟ͑Δ
• Ұͭͷख๏͚ͩͰΰϦԡ͠͠Α͏ͱ͍ͯ͠ͳ ͍͔ʁ • ଞʹָͳํ๏͕ͳ͍͔ݕূ͢Δɻ·ͨɺࣅ ͨΑ͏ͳΞϓϦ͕ͳ͍͔୳ͯ͠ΈΔ ΞχϝʔγϣϯͷDebug มͳಈ͖Λ͍ͯͨ͠Β2/2 ҎԼͷ߲ΛٙͬͯΈ͍͍͔ͯ
2018.2.8 • Shared Element Transitionαϯϓϧίʔυ ࣗମ؆୯ͳͷ͕ଟ͍͚Ͳɺ࣮ࡍʹΈࠐ ΉͱͳΔͱɺϨΠΞτϑΝΠϧͷ࡞Γํ ͕ඞཁʹͳΔ • Shared
Element TransitionҰ࣌ఀࢭ/࠶։ ͕ίϯτϩʔϧͰ͖Δ • ͜·ͬͨΒɺҰ୴Ϧηοτͯ͠ߟ͑Δɻ·ͨɺ ࣅͯΔΞϓϦΛ୳ͯ͠Α͘؍͢Δ ·ͱΊ ·ͱΊ
2018.2.8 Thanks!