Transitions Frameworkã䜿çšãããšãããŸããŸãªã¢ãã¡ãŒã·ã§ã³ããã°ããç°¡åã«äœæã§ããŸãã ãã®ãããiFunnyã®éçºããã»ã¹ã§ã¯ããã®ããŒã«ããããééããããšã¯äžå¯èœã§ããã èªè ã«ã¯ããã©ã³ãžã·ã§ã³APIã䜿çšããç¹å¥ãªã±ãŒã¹ãæäŸãããŸã-ã·ãŒã ã¬ã¹ãªå¹æã§ã¢ã¯ãã£ããã£éã®ãã©ã³ãžã·ã§ã³ã®ã¢ãã¡ãŒã·ã§ã³ãäœæããŸãã
èŠèŠçãªèŠ³ç¹ããããã©ã³ãžã·ã§ã³ãã¬ãŒã ã¯ãŒã¯ã«è¡šç€ºãããã¢ã¯ãã£ããã£éã®ãã©ã³ãžã·ã§ã³ã®ã¢ãã¡ãŒã·ã§ã³ã¯ãéåžžã®ã¢ãã¡ãŒã·ã§ã³ãšå ±éèŠçŽ ãæã€ã¢ãã¡ãŒã·ã§ã³ã®2ã€ã®ã¿ã€ãã«åé¡ã§ããŸãã äžè¬çãªèŠçŽ ã䜿çšããã¢ãã¡ãŒã·ã§ã³ã®æŠå¿µã¯ã
å³ 1.ã¢ã¯ãã£ããã£ãšå ±éèŠçŽ éã®é·ç§»ã®ã¢ãã¡ãŒã·ã§ã³
ããããé·ã玹ä»ã奜ããªäººã¯ããªãã®ã§ããã®ã¿ã€ãã®ã¢ãã¡ãŒã·ã§ã³ãiFunnyã¢ããªã±ãŒã·ã§ã³ã§ã©ã®ããã«äœæãããããšãã話ã«ç§»ããŸãããã æåã®äŸãšããŠãå³ã«ç€ºãã¢ãã¡ãŒã·ã§ã³ãèããŸãã 2.䜿çšããã«ã¯ãAndroidããŒãžã§ã³5.0以éãå¿ èŠã§ãã
å³ 2.ãŠãŒã¶ãŒèªèšŒç»é¢ã§ã®ã¢ã¯ãã£ããã£éã®é·ç§»ã®ã¢ãã¡ãŒã·ã§ã³
ãŠãŒã¶ãŒã®èŠ³ç¹ããèŠããšãããã§ã¯çããããšã¯äœããããŸããã1ã€ã®ç»é¢ãåçŽãªã¢ãã¡ãŒã·ã§ã³ã§ãã ãã ãããæ³åã®ãšããããå éšãã¯ã1ã€ã®å ±éèŠçŽ ãæã€2ã€ã®ç»é¢éã®ç§»è¡ã§ãã
ãã®ãããªãã©ã³ãžã·ã§ã³ãäœæããæåã®ã¹ãããã¯ãå¥åŠãªããšã«ããã®èŠçŽ èªäœãéžæããäž¡æ¹ã®ã¢ã¯ãã£ããã£ã®ã¬ã€ã¢ãŠãã§ãã®äœçœ®ã決å®ããããšã§ãã ãã®åŸãéžæããã¢ã€ãã ã衚瀺ããåãã¥ãŒã®èª¬æã§ãandroidïŒtransitionNameå±æ§ãè¿œå ããandroidïŒidãååšããªãå Žåã¯ããããå²ãåœãŠãå¿ èŠããããŸãã
ç§ãã¡ã®å Žåããããã¯æ¬¡ã®åœ¢åŒã®éåžžã®ImageViewã§ãã
<ImageView android:layout_width="40dp" android:layout_height="40dp" android:layout_gravity="center" android:transitionName="@string/email_auth_transition" app:srcCompat="@drawable/ic_ifunny_logo" />
ããã§2ã€ã®éèŠãªç¹ã«æ³šæããŠãã ããã ãŸããäž¡æ¹ã®ImageViewã§ãåãtransitionNameãèšå®ããå¿ èŠããããŸããããã¯è«ççã§ãã 第äºã«ãImageViewã䜿çšããŠããããã2ã€ã®ç°ãªããªãœãŒã¹ã䜿çšãããšäºæãã¬çµæãçããå¯èœæ§ãããããïŒå°ãªããšãã¢ãã¡ãŒã·ã§ã³ã®éå§ãšçµäºã§ã¢ãã¡ãŒã·ã§ã³ãã¥ãŒãç¹æ» ãããããïŒãã³ã³ãã³ãã¯åãã§ãªããã°ãªããŸããã
2çªç®ã®ã¹ãããã§ã¯ãèµ·åãããïŒ2çªç®ã®ïŒã¢ã¯ãã£ããã£ã®ãªãã·ã§ã³ãè¿œå ããŠãéå§æã«ã¢ãã¡ãŒã·ã§ã³ãéå§ããå¿ èŠãããããšãéç¥ããå¿ èŠããããŸãã
ã泚æ ã2çªç®ããšã¯ãå®è¡ãããå¿ èŠã®ããé·ç§»ã§ããããªã¬ãŒãããã¢ã¯ãã£ããã£ãæå³ãããæåããšã¯éå§ã¢ã¯ãã£ããã£ãæå³ããŸãã
ããã¯æ¬¡ã®ããã«è¡ãããŸãã
Bundle bundle = null; if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { View v = activity.findViewById(R.id.auth_logo); if (v != null) { ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(activity, v, activity.getString(R.string.email_auth_transition)); bundle = options.toBundle(); } } Intent intent = new Intent(activity, SecondActivity.class); if (bundle == null) { activity.startActivity(intent); } else { activity.startActivity(intent, bundle); }
äžèšã®ãªã¹ãïŒ
- R.id.auth_logo-ã¢ãã¡ãŒã·ã§ã³ã§äœ¿çšãããæåã®ã¢ã¯ãã£ããã£ã®ImageViewã
- ã¢ã¯ãã£ããã£-æåã®ã¢ã¯ãã£ããã£ã
- R.string.email_auth_transition-äž¡æ¹ã®ImageViewã®ã¬ã€ã¢ãŠãã«ä»¥åæ®ã£ãŠããã©ãã«ã
- SecondActivity.class-2çªç®ã®ã¢ã¯ãã£ããã£ã
ãããŠä»ã泚ææ·±ãèªè ã¯å°æããŠãããããããŸããïŒåºè«ã¯APIã¬ãã«19ãAPIã¬ãã«21ã®äŸã®äœ¿çšãæ±ã£ãŠãããäžèšã®ãªã¹ãã«ã¯APIã¬ãã«22ã®å¶éããããŸããæ®å¿µãªãããã³ãŒããæžããšããé·ç§»ã¢ãã¡ãŒã·ã§ã³ã¯å ±éã®èŠçŽ ã§APIã¬ãã«21ã®æºåž¯é»è©±ã§ã¯æ£ããåäœããªãå¯èœæ§ããããŸããããã¯ãäžè¬çãªã¢ãã¡ãŒã·ã§ã³ã®ã¹ããŒããŠã³ãšãç¹ã«ã¢ãã¡ãŒã·ã§ã³åããããã¥ãŒã®ã¢ãŒãã£ãã¡ã¯ãã®åœ¢ã§çŸããŸãã æ¢ã«ãããã¯ã«ç²ŸéããŠããå Žåã¯ããã®åäœã®çç±ããã³/ãŸãã¯èª¬æãããŠããåé¡ã解決ããæ¹æ³ãç¥ã£ãŠãã-ã³ã¡ã³ãã§ãããæããŠãã ããã
3çªç®ã®ã¹ãããã§ã¯ãé·ç§»ã¢ãã¡ãŒã·ã§ã³ãèšè¿°ããå¿ èŠããããŸãã ã¢ãã¡ãŒã·ã§ã³ãã¥ãŒãç¶ããã¹ãšããã¥ãŒèªäœã®å€æãæå®ããŸãã ãããè¡ãã«ã¯ã次ã®å 容ã®å¥åã®ãã¡ã€ã«projectName / src / main / res / transitions / email_auth_transition.xmlãäœæããŸãã
<?xml version="1.0" encoding="utf-8"?> <transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:transitionOrdering="together"> <changeBounds/> <changeImageTransform/> </transitionSet>
ã¡ãã£ãšããçè«ã transitionSetã¿ã°ã¯ãã¢ãã¡ãŒã·ã§ã³åããããã¥ãŒã«äžåºŠã«é©çšãããè€æ°ã®å€æãèšè¿°ããããšãç®çãšããŠããŸãã transitionOrderingãã©ã¡ãŒã¿ãŒã¯ããããã®å€æãé©çšãããé åºãæ åœããŸãã ç§ãã¡ã®å Žåããããã¯åæã«äœ¿çšãããŸãã Transitions Frameworkã«ã¯ãããã€ãã®çš®é¡ã®æ¢è£œã®å€æãæ瀺ãããŠããŸãã å®å šãªãªã¹ãã¯ãã®ããŒãžã«ãããŸã ã changeBoundsãšchangeImageTransformã®2ã€ã®ç¹å®ã®ãã®ã«çŠç¹ãåœãŠãŸãã
1ã€ç®ã¯ããã¥ãŒãµã€ãºã®å€æçšã§ãã 2çªç®ã¯ImageViewã§ã®ã¿åäœãã1çªç®ãšçµã¿åãããŠäœ¿çšââããããšã§ããµã€ãºã ãã§ãªãImageViewã®åœ¢ç¶ãå€æŽã§ããŸãã å€æããŒã¿ã䜿çšããŠãå³ã«ç€ºãç»åãµã€ãºå€æŽã¢ãã¡ãŒã·ã§ã³ã®åºåãååŸããŸãã 2.ã¢ãã¡ãŒã·ã§ã³åããããã¥ãŒã®ã¢ãŒã·ã§ã³ã®ã¿ã€ããæå®ããªãå Žåãæçã®ãã¹ã«æ²¿ã£ãŠç§»åããŸãã 2çªç®ã®äŸã§ã¯ãããèå³æ·±ã亀éæ段ãæ€èšããŸãã
ã¢ãã¡ãŒã·ã§ã³ãäœæããæåŸã®ã¹ãããã¯ãäž¡æ¹ã®ã¢ã¯ãã£ããã£ã®ããŒãã§å®£èšããããšã§ãã ãããè¡ãã«ã¯ã次ã®æ¹æ³ã§èª¬æãç·šéããŸãïŒãŸãã¯ãprojectName / src / main / res / values-v22 / theme.xmlãã©ã«ããŒã«æ°ãã説æãäœæããŸãïŒã
<style name="Theme.FirstActivity" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowActivityTransitions">true</item> </style> <style name="Theme.SecondActivity" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowActivityTransitions">true</item> <item name="android:windowSharedElementEnterTransition"> @transition/email_auth_transition </item> <item name="android:windowSharedElementExitTransition"> @transition/email_auth_transition </item> </style>
ããã«ïŒ
- androidïŒwindowActivityTransitionsã¯é·ç§»ã¢ãã¡ãŒã·ã§ã³ãæå¹ã«ããŸãã
- androidïŒwindowSharedElementEnterTransitionã¯ãæåã®ã¢ã¯ãã£ããã£ãã2çªç®ã®ã¢ã¯ãã£ããã£ãžã®é·ç§»ã®ã¢ãã¡ãŒã·ã§ã³ã®èª¬æãå«ããã¡ã€ã«ãæããŸãã
- androidïŒwindowSharedElementExitTransitionã¯ã2çªç®ã®ã¢ã¯ãã£ããã£ããæåã®ã¢ã¯ãã£ããã£ã«æ»ããšãã«ãé·ç§»ã¢ãã¡ãŒã·ã§ã³ã®èª¬æãå«ããã¡ã€ã«ãæããŸãã
OSããŒãžã§ã³ã5.1ãããäœãå Žåãã¢ããªã±ãŒã·ã§ã³ã®ã¯ã©ãã·ã¥ãšãã圢ã§äºæ³ãããçµæãé¿ããããã«ãåãã¹ã¿ã€ã«ã®ããŒããäœæããå¿ èŠãããããšã«æ³šæããŠãã ããã äŸãã°ããããããã¡ã€ã«projectName / src / main / res / values / theme.xmlã«å ¥ããŸãïŒ
<style name="Theme.FirstActivity" parent="Theme.NoActionBar.Translucent"/> <style name="Theme.SecondActivity" parent="Theme.TransparentActionBar"/>
ãããã£ãŠãã¢ã¯ãã£ããã£ããã¢ã¯ãã£ããã£ãžã®é·ç§»ã®ã¢ãã¡ãŒã·ã§ã³ãäœæããã«ã¯ã次ã®ãã®ãå¿ èŠã§ãã
- ã¢ãã¡ãŒã·ã§ã³ãèšè¿°ããŸãïŒãã®å Žåãxmlãã¡ã€ã«ã§ïŒã
- ãããã®ã¢ãã¡ãŒã·ã§ã³ãã¢ã¯ãã£ããã£ããŒãã®xmlèšè¿°ã«è¿œå ããŸãã
- ããŒã¯ã¢ããã§ã¢ãã¡ãŒã·ã§ã³åãããå ±éèŠçŽ ïŒãã¥ãŒïŒãããŒã¯ããŸãã
- 2çªç®ã®ã¢ã¯ãã£ããã£ãéå§ãããšãã«ãèµ·åã¢ãã¡ãŒã·ã§ã³ã§ãã©ã³ãžã·ã§ã³ã¢ãã¡ãŒã·ã§ã³ã䜿çšããå¿ èŠãããããšãæå®ããŸãã
ã芧ã®ãšããããã®ãããªã¢ãã¡ãŒã·ã§ã³ã®äœæã¯ãæåã®äŸã§è¿°ã¹ãããã€ãã®å¶éãé€ããŠããŸã£ããé£ãããããŸããã 次ã«ã2çªç®ã®ããè€éãªäŸãèããŠã¿ãŸãããã ããã§ã¯ãã³ã¡ã³ãã»ã¯ã·ã§ã³ãããŠãŒã¶ãŒãããã¡ã€ã«ã«ç§»åããããšã«èå³ããããŸãïŒå³3ïŒã
å³ 3.ãŠãŒã¶ãŒãããã¡ã€ã«ã®ã³ã¡ã³ãããã¢ãã¡ãŒã·ã§ã³ã移è¡ãã
äžèšã®ãã©ã³ãžã·ã§ã³ãäœæããããã®ãã¹ãŠã®ã¹ãããã¯ããã®ã¢ãã¡ãŒã·ã§ã³ã«ãé©ããŠããŸãã ããããå ±éèŠçŽ ã®å€æã¯å°ãç°ãªã£ãŠå®è£ ãããŸãã 次ã®ãªã¹ãã¯ãäžè¬çãªãarcãèŠçŽ ã®ãµã€ãºå€æŽãšãšãã«ç§»åããæ¹æ³ã瀺ããŠããŸãã
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"> <changeBounds> <arcMotion android:maximumAngle="90" android:minimumHorizontalAngle="90" android:minimumVerticalAngle="0" /> </changeBounds> </transitionSet>
2çªç®ã®äŸã®è€éãã¯äœã§ããïŒ æåã®ã±ãŒã¹ã§ã¯ãã¢ããªã±ãŒã·ã§ã³èªäœã®ãªãœãŒã¹ããã®ã€ã¡ãŒãžã䜿çšãããŸãããããã§ã¯ãã€ã¡ãŒãžã¯ãããã¯ãŒã¯ããããŠã³ããŒããããŸãã ããã«ãã³ã¡ã³ãã®å ŽåããŠãŒã¶ãŒã®ã¢ãã¿ãŒã®ç»åã¯ãããã¡ã€ã«ã®è§£å床ãããäœã解å床ã§æ®åœ±ãããŸãã ãã®ããã2çªç®ã®ã¢ã¯ãã£ããã£ã«æåã®ç»åã§äœ¿çšãããŠããç»åãžã®ã¢ã¯ã»ã¹ãèš±å¯ããã ãã§ãªããã¢ãã¡ãŒã·ã§ã³ã®æåŸã«å¿ èŠãªç»åãããé«å質ã§èªã¿èŸŒãå¿ èŠããããŸãã ãããã£ãŠã2ã€ã®åé¡ãå€æããŸãã
æåã®åé¡ã解決ããã«ã¯ãå人çã«ã€ã¡ãŒãžããã£ã¹ã¯ã«ãã£ãã·ã¥ãããã2çªç®ã®ã¢ã¯ãã£ããã£ã®ãã©ã¡ãŒã¿ãŒã§ãã®ã¢ãã¬ã¹ã転éããŸãã ãã ãããã®åé¡ã®è§£æ±ºçã¯ãã¢ããªã±ãŒã·ã§ã³ã§äœ¿çšãããç»åã®ããŠã³ããŒãã«äœ¿çšãããã©ã€ãã©ãª-Glideã«è»¢éãããŸããã ã€ã¡ãŒãžãããŒããããšãã«ãdiskCacheStrategyãã©ã¡ãŒã¿ãŒïŒDiskCacheStrategy.SOURCEïŒãè¿œå ããã ãã§ãã©ã€ãã©ãªèªäœã«ãã£ãŠãã£ãã·ã¥ãããŸãïŒGlideããŒãžã§ã³3.xã«é¢é£ïŒã ãããã£ãŠã2çªç®ã®ã¢ã¯ãã£ããã£ãããã®ãªãœãŒã¹ã«å床ã¢ã¯ã»ã¹ããå Žåããã£ãã·ã¥ããããã¡ã€ã«ã䜿çšãããŸããããã«ãããã¢ãã¡ãŒã·ã§ã³åãããImageViewã®ç¹æ» ãåé¿ã§ããŸãã
2çªç®ã®åé¡ãéåžžã«ç°¡åã«è§£æ±ºãããŸãã ãã©ã³ãžã·ã§ã³ãã¢ãã¡ãŒã·ã§ã³åãããŠããéããŠãŒã¶ãŒãããã¡ã€ã«ãšé«è§£å床ã®ã¢ãã¿ãŒããããã¯ãŒã¯ããããŠã³ããŒãããããã®å®äºãåŸ ã¡ãŸãã äž¡æ¹ã®æ¡ä»¶ïŒã¢ãã¡ãŒã·ã§ã³ã®å®äºãšããŠã³ããŒãã®å®äºïŒãæºãããããšããã«ããŠãŒã¶ãŒã®ã¢ãã¿ãŒãæŽæ°ãããŸãã ã¢ãã¡ãŒã·ã§ã³ã®ã¹ããŒã¿ã¹ãå€åãããšãã«åŒã³åºãããã³ãŒã«ããã¯ãå®è£ ããç¹å¥ãªãªã¹ããŒã䜿çšãããšããã®åäœãå®çŸã§ããŸãã ãããè¡ãã«ã¯ã2çªç®ã®ã¢ã¯ãã£ããã£ã«å±ãããã©ã°ã¡ã³ãã§ããã®ãªã¹ããŒãèšå®ããŸãã
@Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { getActivity().getWindow().getSharedElementEnterTransition() .addListener(mEnterTransitionListener); } setAvatar(); }
ããã§æ¬¡ã®ããšãèµ·ãããŸãã
- getSharedElementEnterTransitionïŒïŒã䜿çšããAddListenerïŒïŒã¯ãã¢ã¯ãã£ããã£ã®å€èŠ³ãã¢ãã¡ãŒã·ã§ã³åããããã«ãªã¹ããŒãèšå®ããŸãã
- setAvatarïŒïŒã¡ãœããã¯ãã¢ãã¿ãŒïŒæ¢ã«ãã£ãã·ã¥ã«ããïŒã®ããŠã³ããŒããšã€ã³ã¹ããŒã«ãè©Šã¿ãŸãã
ãªã¹ããŒã®å®è£ æ¹æ³ãæ£ç¢ºã«æ€èšããŠãã ããã
private Transition.TransitionListener mEnterTransitionListener = new Transition.TransitionListener() { @Override public void onTransitionStart(Transition transition) { } @Override public void onTransitionEnd(Transition transition) { onProfileUpdated(); } @Override public void onTransitionCancel(Transition transition) { } @Override public void onTransitionPause(Transition transition) { } @Override public void onTransitionResume(Transition transition) { } };
onProfileUpdatedïŒïŒã¡ãœããã§ããããã¡ã€ã«ã®ã³ã³ãã³ããæŽæ°ããŸãã ãšã¢ãã¿ãŒã
å ±éã®èŠçŽ ãç»é¢ãè¶ ããå Žåãåå¥ã«èšåãã䟡å€ããããŸãã ãã®ç¹åŸŽã¯ãããžãã¯ãšã¯å察ã«ïŒãŸãã¯ããžãã¯ã«åŸã£ãŠïŒãã©ã³ãžã·ã§ã³ã¢ãã¡ãŒã·ã§ã³ãå®è¡ãããéåžžã«é¢çœãããã«èŠãããšããäºå®ã«ãããŸãïŒå³4ïŒã
å³ 4.ã³ã¡ã³ãå ã®ãããã¡ã€ã«ããã®æ»ãã®ã¢ãã¡ãŒã·ã§ã³
ãã®åäœãåé¿ããã«ã¯ãäžè¬çãªèŠçŽ ãç»é¢ãé¢ãããšãã«ãView.VISIBLEãšã¯ç°ãªãå¯èŠæ§ãèšå®ããã ãã§ååã§ãã
äžè¬çã«ããã©ã³ãžã·ã§ã³ãã¬ãŒã ã¯ãŒã¯ã¯ãã¢ãã¡ãŒã·ã§ã³ãäœæããããã®ã·ã³ãã«ã§åŒ·åãªããŒã«ã§ãããšèšããŸãã ã¢ã¯ãã£ããã£éã®é·ç§»ã®ã¢ãã¡ãŒã·ã§ã³ã®ã¿ã«éå®ããããã®ã§ã¯ãããŸãã-ãã®èšäºã§ã¯ããã®äœ¿çšã®ç¹å¥ãªã±ãŒã¹ã®ã¿ãæ€èšããŸããã ãŸããæäŸãããå€æã«å ããŠãç¬èªã®å€æãäœæããããšãã§ããŸãããããã¯å¥ã®æçš¿ã«å€ããå®å šã«ç°ãªãã¹ããŒãªãŒã§ãã
PSãããŠãiFunnyã®ã¢ãã¡ãŒã·ã§ã³ãã©ã®ããã«èãããããã«ã€ããŠã¯ã ãã¡ããã芧ãã ãã ã