Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
View Animation
Search
satsukies
October 02, 2017
Programming
1
840
View Animation
View Animation in Android
satsukies
October 02, 2017
Tweet
Share
More Decks by satsukies
See All by satsukies
5分で作るモックサーバー
satsukies
0
1.3k
Android スキルセットをフル活用して始めるスマートテレビアプリ開発
satsukies
1
920
Android TVに関するアップデート / What's new on Android TV
satsukies
0
210
Kotlin Nativeでクロスプラットフォーム開発 / Cross-platform development with Kotlin Native
satsukies
1
930
Navigation Component
satsukies
5
4k
「OK google, プロジェクトのbuildして」
satsukies
2
1.6k
いまさら始めるInstant App
satsukies
1
410
Other Decks in Programming
See All in Programming
Railsアプリケーションと パフォーマンスチューニング ー 秒間5万リクエストの モバイルオーダーシステムを支える事例 ー Rubyセミナー 大阪
falcon8823
5
1.1k
脱Riverpod?fqueryで考える、TanStack Queryライクなアーキテクチャの可能性
ostk0069
0
150
Deep Dive into ~/.claude/projects
hiragram
14
2.6k
Google Agent Development Kit でLINE Botを作ってみた
ymd65536
2
250
VS Code Update for GitHub Copilot
74th
2
650
ruby.wasmで多人数リアルタイム通信ゲームを作ろう
lnit
3
490
Is Xcode slowly dying out in 2025?
uetyo
1
280
PostgreSQLのRow Level SecurityをPHPのORMで扱う Eloquent vs Doctrine #phpcon #track2
77web
2
530
git worktree × Claude Code × MCP ~生成AI時代の並列開発フロー~
hisuzuya
1
570
なぜ「共通化」を考え、失敗を繰り返すのか
rinchoku
1
650
プロダクト志向なエンジニアがもう一歩先の価値を目指すために意識したこと
nealle
0
130
PHPでWebSocketサーバーを実装しよう2025
kubotak
0
290
Featured
See All Featured
GitHub's CSS Performance
jonrohan
1031
460k
Thoughts on Productivity
jonyablonski
69
4.7k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
44
2.4k
RailsConf 2023
tenderlove
30
1.1k
Facilitating Awesome Meetings
lara
54
6.4k
The Invisible Side of Design
smashingmag
301
51k
Practical Orchestrator
shlominoach
189
11k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
31
1.3k
Done Done
chrislema
184
16k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Intergalactic Javascript Robots from Outer Space
tanoku
271
27k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
50k
Transcript
7JFX"OJNBUJPO 4BUPTIJ5BLFEB "CFNB57*OD
8IPJT
8IPJT ాɹஐ 5BLFEBɹ4BUPTIJ ˡTBUTVLJFT ɹɹ$ZCFS"HFOUʹ৽ଔೖࣾ ʙɹ"CFNB57ʹ"OESPJEΤϯδχΞͰଐ
"OJNBUJPO
"OJNBUJPO 7JFX"OJNBUJPO 1SPQFSUZ"OJNBUJPO %SBXBCMF"OJNBUJPO
"OJNBUJPO 7JFX"OJNBUJPO 1SPQFSUZ"OJNBUJPO %SBXBCMF"OJNBUJPO BMQIB SPUBUF TDBMF USBOTMBUF ͍͍͢ɾ؆୯ ݟ͚͕ͨͩมԽ͢ΔΞχϝʔγϣϯ
// viewͷalpha͕0͔Β13ඵ͔͚ͯมԽ͢ΔΞχϝʔγϣϯ (findViewById(R.id.image_view) as? ImageView)?.apply { startAnimation(AlphaAnimation(0f, 1f).apply { duration = 3000 }) }
"OJNBUJPO 7JFX"OJNBUJPO 1SPQFSUZ"OJNBUJPO "1*͔Β࣮͞Εͨ৽͍͠BOJNBUPS ෳࡶͳΞχϝʔγϣϯΛදݱՄೳ ݟ͚ͨͩͰͳ࣮͘ࡍͷҐஔมԽ <set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering=“together"> <objectAnimator
android:duration="3000" android:propertyName=“alpha" android:valueFrom="0f" android:valueTo="1f"/> <objectAnimator android:duration="3000" android:propertyName="translationY" android:valueFrom="0dp" android:valueTo="100dp"/> </set> %SBXBCMF"OJNBUJPO
"OJNBUJPO 1SPQFSUZ"OJNBUJPO %SBXBCMF"OJNBUJPO ը૾ϦιʔεΛෳຕར༻ͯ͠ ύϥύϥອըͷΑ͏ʹ࠶ੜͤ͞Δ 7JFX"OJNBUJPO <?xml version="1.0" encoding="utf-8"?> <animation-list
xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false" android:visible="true" > <item android:drawable=“@drawable/pict0" android:duration="300" /> <item android:drawable="@drawable/pict1" android:duration="300" /> <item android:drawable="@drawable/pict2" android:duration="300" /> <item android:drawable="@drawable/pict3" android:duration="300" /> <item android:drawable="@drawable/pict4" android:duration="300" /> </animation-list>
.BUFSJBM%FTJHO
.BUFSJBM%FTJHO w .BUFSJBMJTUIFNFUBQIPS w #PME HSBQIJD JOUFOUJPOBM w .PUJPOQSPWJEFTNFBOJOH ҙຯͷ͋Δಈ͖ΛϢʔβʹࣔ͢͜ͱͰ
ɾࢹ֮తʹҙΛҾ͖͚ͭΔ ɾཁૉͷग़ݱมܗɺҠಈΛ௨ͯ͡࿈ଓੑΛ͑Δ ը໘ભҠ͕࣌࠷࿈ଓੑ͕ࣦΘΕͦ͢͏
ը໘ભҠͷΧελϚΠζ
ը໘ભҠͷΧελϚΠζ https://developer.android.com/training/material/animations.html#Transitions (PPHMF%FWFMPQFSTͷ ʮΞΫςΟϏςΟભҠΛΧελϚΠζ͢ΔʯʹΑΕ ȜȄȨǠȩȅǴǢȱǠȕȨƵ!CTIVITYTRANSITIONS ᮊǠǭȄǡȑȄǡჟᮋƮƶųΒឬƠǒᖽᇽƵᣨƮƵ Ы˗NjدъǙឬƟƭųओƵϜǑଖƏƲᗆᗉƱ ƫƱƓǑǙেƦƢDžƠŴ લޙͷΞΫςΟϏςΟͰڞ௨ͷΞΠίϯը૾ݟग़͠ςΩετͳͲ͕ଘࡏ͢Δ߹ʹ ڞ௨͢Δཁૉͷද͕ࣔҾ͖ܧ͕Ε͍ͯΔΑ͏ʹݟͤΔ͜ͱͰ࿈ଓੑΛදݱ͢Δ
"DUJWJUZ5SBOTJUJPOTͷछྨ
"DUJWJUZ5SBOTJUJPOTͷछྨ &OUFS &YJU 4IBSFE&MFNFOUT
"DUJWJUZ5SBOTJUJPOTͷछྨ &OUFS &YJU 4IBSFE&MFNFOUT "DUJWJUZͷWJFX͕ͲͷΑ͏ʹը໘ೖͬͯ͘Δ͔Λܾఆ
"DUJWJUZ5SBOTJUJPOTͷछྨ &OUFS &YJU 4IBSFE&MFNFOUT "DUJWJUZͷWJFX͕ͲͷΑ͏ʹը໘͔Βग़ͯߦ͔͘Λܾఆ
"DUJWJUZ5SBOTJUJPOTͷछྨ &OUFS &YJU 4IBSFE&MFNFOUT ը໘্ʹ͋Δڞ௨ͷཁૉʢྫ͑*NBHF7JFXͱ͔ʣΛ ͲͷΑ͏ʹΞχϝʔγϣϯͤ͞Δ͔ɻ "1*͔Β࣮͞Εར༻Մೳʂ αϙʔτϥΠϒϥϦʹೖ͍ͬͯͳ͍ͷ͕ͪΐͬͱ೦
(PPHMF1MBZ4UPSF
None
Ґͩͱಈ͖͕গͳͯ͘ Α͔͘Βͳ͍ʁ!
Ξχϝʔγϣϯ εέʔϧY
"CFNB57ʹ
None
ͳΒ͜͜ʹ ΞχϝʔγϣϯΛʂ
7JFX"OJNBUJPO 4BUPTIJ5BLFEB "CFNB57*OD
7JFX"OJNBUJPO 4BUPTIJ5BLFEB "CFNB57*OD 5SBOTJUJPO
#BTJDJNQMFNFOU
#BTJDJNQMFNFOU /PSNBM.BTUFS"DUJWJUZLU val intent = Intent(context, SharedMasterActivity::class.java) val optionsCompat =
ActivityOptionsCompat.makeSceneTransitionAnimation( this, targetView, targetView.transitionName) startActivity(intent, optionsCompat.toBundle()) ΞχϝʔγϣϯରͷWJFX //viewͷΠϯελϯεϝιου targetView.setTransitionName("hogehoge") //ViewCompatΫϥεͷΫϥεϝιου ViewCompat.setTransitionName(targetView, "hogehoge") android:transitionName="hogehoge"
#BTJDJNQMFNFOU XJUIඇಉظ௨৴ ભҠઌͱભҠݩͰผʑͷը૾Λ͍ͬͯΔ߹ʜ ը૾ͷऔಘ͕Ξχϝʔγϣϯ։࢝ʹؒʹ߹Θͳ͍ʂ
"EWBODFEJNQMFNFOU
"EWBODFEJNQMFNFOU ݺͼग़ͨ͠λΠϛϯάͰ5SBOTJUJPO"OJNBUJPOΛ։࢝ͤ͞Δ QPTUQPOF&OUFS5SBOTJUJPO TUBSU1PTUQPOFE&OUFS5SBOTJUJPO 5SBOTJUJPO"OJNBUJPOͷ։࢝Λࢭ͢Δ Ξχϝʔγϣϯͷ։࢝λΠϛϯάΛ ίʔυଆͰίϯτϩʔϧՄೳ
"EWBODFEJNQMFNFOU override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) supportPostponeEnterTransition() // Ξχϝʔγϣϯࢭ
~~~~~~~~~~~~~~~ fun startEnterTransition() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return supportStartPostponedEnterTransition(); // Ξχϝʔγϣϯ࠶։ }
"EWBODFEJNQMFNFOU (MJEF1JDBTTPͷ$BMMCBDLʹࠐΜͰΈΔ ImageView targetImageView = (ImageView)findViewById(R.id.image_header); //Glideͷ߹(4.0-RC0) Glide.with(this) .load("http://hogehoge.com/fugafuga") .listener(new
RequestListener() { @Override public boolean onResourceReady(Object resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { startPostponedEnterTransition() return false; } }) .into(targetImageView); //Picassoͷ߹ Picasso.with(this) .load("http://hogehoge.com/fugafuga").into(targetImageView, new Callback(){ @Override public void onSuccess() { startPostponedEnterTransition() } });
ΫϦοΫ͔ͯ͠ΒΞχϝʔγϣϯ·Ͱͷػ͕࣌ؒࢥͬͨҎ্ʹ͍"
ϢʔβମݧΛҡ͍࣋ͨ͠
ϢʔβମݧΛҡ͍࣋ͨ͠ ಛʹߟ͑ͣγϯϓϧʹΞχϝʔγϣϯͤ͞Δͱ ɾΞϓϦ͕ϑϦʔζ͍ͯ͠ΔΑ͏ʹݟ͑ͯ͠·͏ ɾը૾͕ϩʔυ͞ΕΔ·ͰCBDLHSPVOE͕ݟ͑ݟ͑ ը૾ͷಡΈࠐΈΛͬͯΞχϝʔγϣϯ͢Δͱ ɾ్தͰը૾͕ϩʔυ͞Εͯද͕ࣔมʹͳΔ͜ͱ Ͳ͏ʹ͔ͯ͠ը૾Λૉૣ͘ϩʔυ͍ͨ͠ʜ"
None
ϢʔβମݧΛҡ͍࣋ͨ͠ (MJEFͷαϜωΠϧදࣔػೳΛ׆༻ ɾಉ͡WJFXͰෳͷը૾Λಉ࣌ʹಡΈࠐΊΔ ɾαϜωΠϧը૾ͷMPBEʹରͯ͠DBMMCBDL͕͚ͭΒΕΔ αϜωΠϧදࣔ Ξχϝʔγϣϯ։࢝ ݩը૾දࣔ
5SBOTJUJPOXJUIUIVNC
5SBOTJUJPOXJUIUIVNC ᶃ*OUFOUʹΩϟογϡࡁΈը૾ͷ63-ΛͤΔ ᶄαϜωΠϧಡΈࠐΈʹ*OUFOUͷ63-Λ͏
5SBOTJUJPOXJUIUIVNC ᶃ*OUFOUʹΩϟογϡࡁΈը૾ͷ63-ΛͤΔ ᶄαϜωΠϧಡΈࠐΈʹ*OUFOUͷ63-Λ͏ binding.getRoot().setOnClickListener(v -> episodeSelectListener.action( ep, ep.getEpisodeListThumbnail().with(options).url(), // ΩϟογϡࡁΈͷը૾URL
binding.episodeThumbnail, binding.vdSeriesThumbnailFreeMark, binding.episodePlayMark)); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Intent intent = new Intent(this, DstActivity.class); intent.putExtra(“extra_url”, thumbnailUrlString);
5SBOTJUJPOXJUIUIVNC ᶃ*OUFOUʹΩϟογϡࡁΈը૾ͷ63-ΛͤΔ ᶄαϜωΠϧಡΈࠐΈʹ*OUFOUͷ63-Λ͏ //͢ͰʹMasterActivityͰऔಘࡁΈͰ͋Ζ͏ը૾ΛαϜωΠϧͱͯ͠ར༻͢Δ .thumbnail( Glide.with(imageView.getContext()) .load(imageThumbURL) .listener(new RequestListener<Drawable>() {
@Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) return false; } @Override public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) { supportStartPostponedEnterTransition(); // ಡΈࠐΈྃͰΞχϝʔγϣϯ࣮ߦ return false; }}) .apply(new RequestOptions().skipMemoryCache(true) .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC))) .into(imageView);
ରࡦલ ରࡦޙ
"CFNB57BQQʜ
ͦͷଞ5JQT
ͦͷଞ5JQT TUBUVTOBWJHBUJPOCBSʹඃͤͳ͍ WJFX͕ݟΕͯͨΒΞχϝʔγϣϯ͠ͳ͍
ͦͷଞ5JQT TUBUVTOBWJHBUJPOCBSʹඃͤͳ͍ εςʔλεόʔφϏήʔγϣϯόʔ 4IBSFE&MFNFOU5SBOTJUJPOʹؚΊΔ // navigation bar View nav =
findViewById(android.R.id.navigationBarBackground); // status bar View stat = findViewById(android.R.id.statusBarBackground); Pair<View, String> navPair = new Pair<>(nav, "nav"); Pair<View, String> statPair = new Pair<>(stat, "stat"); ActivityOptionsCompat.makeSceneTransitionAnimation(this, navPair, statPair); WJFX͕ݟΕͯͨΒΞχϝʔγϣϯ͠ͳ͍
ͦͷଞ5JQT TUBUVTOBWJHBUJPOCBSʹඃͤͳ͍ WJFX͕ݟΕͯͨΒΞχϝʔγϣϯ͠ͳ͍
ͦͷଞ5JQT TUBUVTOBWJHBUJPOCBSʹඃͤͳ͍ ಈతͳΞχϝʔγϣϯ࣮ߦՄ൱ͷ੍ޚ ɾը໘ճస͕ൃੜͨ͠ΒΞχϝʔγϣϯΛ͠ͳ͍ ɾαϜωΠϧ͕ݟΕ͍ͯΔͱ͖Ξχϝʔγϣϯ͠ͳ͍ 4IBSFE&MFNFOU$BMMCBDLͰ ΞχϝʔγϣϯͷΩϟϯηϧॲཧΛ࣮
ͦͷଞ5JQT TUBUVTOBWJHBUJPOCBSʹඃͤͳ͍ ಈతͳΞχϝʔγϣϯ࣮ߦՄ൱ͷ੍ޚ 4IBSFE&MFNFOU$BMMCBDLͰ ΞχϝʔγϣϯͷΩϟϯηϧॲཧΛ࣮ setEnterSharedElementCallback(new SharedElementCallback() { @Override public
void onMapSharedElements(List<String> names, Map<String, View> sharedElements) { // Ξχϝʔγϣϯରview͕ݟΕ͍ͯΔ߹ΞχϝʔγϣϯΛ࣮ߦ͠ͳ͍ shouldClearSharedElements |= !Stream.of(sharedElements) .filter(item -> item.getValue() != null) .allMatch(item -> viewBehavior.checkViewContains(item.getValue())); if (shouldClearSharedElements) { names.clear(); sharedElements.clear(); } } });
ͦͷଞ5JQT TUBUVTOBWJHBUJPOCBSʹඃͤͳ͍ ಈతͳΞχϝʔγϣϯ࣮ߦՄ൱ͷ੍ޚ શදࣔ ݟΕ
4VNNBSZ
4VNNBSZ "OJNBUJPOʹछྨ͕͍Ζ͍Ζ "DUJWJUZ5SBOTJUJPO࿈ଓੑΛ͑ΔͷʹޮՌత গ͠ͷίʔυमਖ਼Ͱ"OJNBUJPOͷద༻͕Մೳ ඇಉظॲཧͱซ༻͢Δ࣌ҙΛ͏ඞཁ͋Γ
4VNNBSZ "OJNBUJPOʹछྨ͕͍Ζ͍Ζ "DUJWJUZ5SBOTJUJPO࿈ଓੑΛ͑ΔͷʹޮՌత গ͠ͷίʔυमਖ਼Ͱ"OJNBUJPOͷద༻͕Մೳ ඇಉظॲཧͱซ༻͢Δ࣌ҙΛ͏ඞཁ͋Γ 7JFX"OJNBUJPO 1SPQFSUZ"OJNBUJPO %SBXBCMF"OJNBUJPO "DUJWJUZ5SBOTJUJPOT
4VNNBSZ "OJNBUJPOʹछྨ͕͍Ζ͍Ζ "DUJWJUZ5SBOTJUJPO࿈ଓੑΛ͑ΔͷʹޮՌత લޙͷΞΫςΟϏςΟͰҎԼͷΑ͏ͳڞ௨ཁૉ͕ଘࡏ͢Δ߹ ɾΞΠίϯը૾ ɾݟग़͠ςΩετ ͜ΕΒͷද͕ࣔҾ͖ܧ͕Ε͍ͯΔΑ͏ʹݟͤΔ͜ͱͰ࿈ଓੑΛදݱ͢Δ গ͠ͷίʔυमਖ਼Ͱ"OJNBUJPOͷద༻͕Մೳ ඇಉظॲཧͱซ༻͢Δ࣌ҙΛ͏ඞཁ͋Γ
4VNNBSZ "OJNBUJPOʹछྨ͕͍Ζ͍Ζ গ͠ͷίʔυमਖ਼Ͱ"OJNBUJPOͷద༻͕Մೳ ඇಉظॲཧͱซ༻͢Δ࣌ҙΛ͏ඞཁ͋Γ "DUJWJUZ5SBOTJUJPO࿈ଓੑΛ͑ΔͷʹޮՌత USBOTJUJPO/BNFͷ ༩ 4IBSFE&MFNFOU 5SBOTJUJPOͷ࣮ߦڐՄ "DUJWJUZ0QUJPOT͖Ͱ
"DUJWJUZ࣮ߦ
4VNNBSZ "OJNBUJPOʹछྨ͕͍Ζ͍Ζ "DUJWJUZ5SBOTJUJPO࿈ଓੑΛ͑ΔͷʹޮՌత গ͠ͷίʔυमਖ਼Ͱ"OJNBUJPOͷద༻͕Մೳ ඇಉظॲཧͱซ༻͢Δ࣌ҙΛ͏ඞཁ͋Γ ඞཁʹԠͯ͡Ξχϝʔγϣϯͷ࣮ߦλΠϛϯάΛ੍ޚ QPTUQPOF&OUFS5SBOTJUJPO TUBSU1PTUQPOFE&OUFS5SBOTJUJPO Ξχϝʔγϣϯͷ ࠶։
Ξχϝʔγϣϯͷ ։࢝ࢭ αϜωΠϧಡΈࠐΈ
5IBOLZPV !TBUTVLJFT