لا توجد قصة حزينة في العالم
من قصة ViewPager'e و SET'e
أود أن أحذر من أن المؤلف هو Android مبتدئ ، لذلك تحتوي المقالة على الكثير من الأخطاء التقنية بحيث يجب تحذيرك من أن البيانات الموثوقة تقنيًا قد تظهر في المقال.
حيث يؤدي الخلفية
طوال حياتي رأيت الخلفية. في بداية عام 2019 ، يوجد بالفعل مشروع طموح للغاية ولكنه لم يكتمل. رحلة غير مثمرة إلى زيوريخ لإجراء مقابلة مع شركة بحث واحدة. الشتاء ، الأوساخ ، لا مزاج. لا توجد قوة ورغبة في زيادة المشروع.
أردت أن أنسى هذه الخلفية الرهيبة إلى الأبد. لحسن الحظ ، أعطاني القدر فكرة - لقد كان تطبيقًا للهاتف المحمول. كانت الميزة الرئيسية هي الاستخدام غير القياسي للكاميرا. بدأ العمل في الغليان. استغرق الأمر بعض الوقت ، والآن أصبح النموذج الأولي جاهزًا. كان إطلاق المشروع يقترب وكان كل شيء على ما يرام ومتناسب ، حتى قررت أن تجعل المستخدم " مناسبًا ".
لا أحد يريد أن ينقر على أزرار القائمة الصغيرة في عام 2019 ، كلهم يريدون أن يسحبوا الشاشات إلى اليمين واليسار. يقال - فعلت ، فعلت - مكسورة. لذلك ظهر ViewPager
الأول في مشروعي (لقد قمت بفك تشفير بعض المصطلحات لنفس الواجهة الخلفية مثلي - فقط انقل المؤشر). و " العنصر المشترك للانتقال" (المشار إليه فيما يلي بـ " ViewPager
أو "النقل") - عنصر التوقيع في " تصميم المواد" ، رفض رفضًا قاطعًا العمل مع ViewPager
، مما يترك لي خيارًا: إما الضربات الشديدة أو الرسوم المتحركة الانتقالية الجميلة بين الشاشات. لم أكن أرغب في رفض أحدهما أو الآخر. لذلك بدأ بحثي.
ساعات الدراسة: العشرات من المواضيع في المنتديات والأسئلة التي لم تتم الإجابة عليها على StackOverflow. بغض النظر عن ما أفتحه ، فقد عرض علي إجراء عملية نقل من RecyclerView إلى ViewPager أو "إرفاق أداة Fragment.postponeEnterTransition()
" غير محددة.
العلاجات الشعبية لم تساعد ، وقررت التوفيق بين ViewPager
Shared Element Transition
بنفسي.
بدأت أفكر: "تظهر المشكلة في الوقت الذي ينتقل فيه المستخدم من صفحة إلى أخرى ...". وبعد ذلك بزغ فجرًا لي: "لن تواجهك مشكلة في SET أثناء تغيير الصفحة ، إذا لم تقم بتغيير الصفحة".
يمكننا القيام بالانتقال في نفس الصفحة ، ثم استبدال الصفحة الحالية بالصفحة الهدف في ViewPager
.
أولاً ، ابتكار شظايا سنعمل بها.
SmallPictureFragment small_picture_fragment = new SmallPictureFragment(); BigPictureFragment big_picture_fragment = new BigPictureFragment();
دعنا نحاول تغيير الجزء في الصفحة الحالية إلى شيء آخر.
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
نطلق التطبيق ونتحول بسلاسة إلى شاشة فارغة. ما السبب؟
اتضح أن حاوية كل صفحة هي ViewPager
نفسها ، دون أي وسطاء مثل Page1Container
، Page2Container
. لذلك ، فقط تغيير صفحة واحدة إلى أخرى لا يعمل ، سيتم استبدال جهاز pager
بأكمله.
حسنًا ، لتغيير محتوى كل صفحة على حدة ، نقوم بإنشاء عدة أجزاء حاوية لكل صفحة.
RootSmallPictureFragment root_small_pic_fragment = new RootSmallPictureFragment(); RootBigPictureFragment root_big_pic_fragment = new RootBigPictureFragment();
لن يبدأ شيء من جديد.
java.lang.IllegalStateException: لا يمكن تغيير معرف الحاوية للجزء BigPictureFragment {...}: كان 2131165289 الآن 2131165290
لا يمكننا إرفاق جزء من الصفحة الثانية ( BigPictureFragment
) BigPictureFragment
الأولى ، لأنه مرفق بالفعل بحاوية الصفحة الثانية.
بعد التشبث بأسناننا ، نضيف المزيد من الأجزاء المزدوجة.
SmallPictureFragment small_picture_fragment_fake = new SmallPictureFragment(); BigPictureFragment big_picture_fragment_fake = new BigPictureFragment();
حصل! يمتد رمز الانتقال الذي قمت بنسخه من GitHub بالفعل المتضمنة بالفعل ويتلاشى الرسوم المتحركة. لذلك ، قبل الانتقال ، اختفت جميع العناصر الثابتة من الجزء الأول ، ثم انتقلت الصور ، وعندئذٍ فقط ظهرت عناصر الصفحة الثانية. للمستخدم ، هذا يبدو وكأنه حركة حقيقية بين الصفحات.
لقد مرت جميع الرسوم المتحركة ، ولكن هناك مشكلة واحدة. لا يزال المستخدم في الصفحة الأولى ، ولكن يجب أن يكون في الصفحة الثانية.
لإصلاح ذلك ، استبدلنا بعناية صفحة ViewPager
المرئية ViewPager
ثانية. ثم نقوم باستعادة محتويات الصفحة الأولى إلى حالتها الأولية.
handler.postDelayed( () -> {
ما هي النتيجة؟ (الرسوم المتحركة - 2.7 ميغابايت) شفرة المصدر بالكامل | public class FragmentTransitionUtil { |
| |
| private static final long FADE_DEFAULT_TIME = 500; |
| private static final long MOVE_DEFAULT_TIME = 1000; |
| |
| public static void perform( |
| MainActivity activity, |
| Fragment previousFragment, |
| Fragment nextFragment, |
| Map<View, String> sharedElements, |
| int nextPage |
| |
| ) { |
| FragmentManager fragmentManager = activity.getSupportFragmentManager(); |
| FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); |
| |
| if (previousFragment != null) { |
| |
| // 1. Exit for Previous Fragment |
| Fade exitFade = new Fade(); |
| exitFade.setDuration(FADE_DEFAULT_TIME); |
| previousFragment.setExitTransition(exitFade); |
| |
| // 2. Shared Elements Transition |
| TransitionSet enterTransitionSet = new TransitionSet(); |
| enterTransitionSet.addTransition( |
| new TransitionSet() { |
| |
| { |
| setOrdering(ORDERING_TOGETHER); |
| addTransition(new ChangeBounds()). |
| addTransition(new ChangeTransform()). |
| addTransition(new ChangeImageTransform()); |
| } |
| } |
| ); |
| |
| enterTransitionSet.setDuration(MOVE_DEFAULT_TIME); |
| enterTransitionSet.setStartDelay(FADE_DEFAULT_TIME); |
| nextFragment.setSharedElementEnterTransition(enterTransitionSet); |
| |
| // 3. Enter Transition for New Fragment |
| Fade enterFade = new Fade(); |
| enterFade.setStartDelay(MOVE_DEFAULT_TIME + FADE_DEFAULT_TIME); |
| enterFade.setDuration(FADE_DEFAULT_TIME); |
| nextFragment.setEnterTransition(enterFade); |
| |
| if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
| if (sharedElements != null) { |
| for (Map.Entry<View, String> viewStringEntry : sharedElements.entrySet()) { |
| View view = viewStringEntry.getKey(); |
| String transName = viewStringEntry.getValue(); |
| view.setTransitionName(transName); |
| |
| fragmentTransaction.addSharedElement( |
| view, |
| transName |
| ); |
| } |
| } |
| } |
| |
| int fragmentContId = ((ViewGroup) previousFragment.getView().getParent()).getId(); |
| fragmentTransaction.replace(fragmentContId, nextFragment); |
| fragmentTransaction.commit(); |
| |
| |
| final Handler handler = new Handler(); |
| handler.postDelayed( |
| () -> { |
| // Stealthy changing page visible to user. He won’t notice! |
| activity.viewPager.setCurrentItem(nextPage, false); |
| FragmentTransaction transaction = fragmentManager.beginTransaction(); |
| // Restore previous fragment. It contains inappropriate view now |
| transaction.replace(fragmentContId, previousFragment); |
| transaction.commitAllowingStateLoss(); |
| }, |
| FADE_DEFAULT_TIME + MOVE_DEFAULT_TIME + FADE_DEFAULT_TIME |
| ); |
| |
| |
| } |
| } |
| |
| } |
يمكن الاطلاع على المشروع على جيثب .
لتلخيص. بدأت الشفرة تبدو أكثر صلابة: فبدلاً من شظتين مبدئيتين ، حصلت على أكثر من 6 أجزاء ، ظهرت فيها تعليمات تتحكم في الأداء واستبدلت الأجزاء في الوقت المناسب. وهذا هو فقط في التجريبي.
في نفس المشروع ، واحدًا تلو الآخر في التعليمات البرمجية ، بدأت النسخ الاحتياطية في الظهور في أكثر الأماكن غير المتوقعة. لم يسمحوا للتطبيق بالانهيار عندما نقر المستخدم على أزرار من الصفحات "الخاطئة" أو قيد عمل الخلفية لشظايا مكررة.
اتضح أن android ليس لديه عمليات رد اتصال لاستكمال عملية النقل ، ووقت تنفيذها تعسفي للغاية ويعتمد على العديد من العوامل (على سبيل المثال ، مدى سرعة تحميل RecyclerView
في الجزء الناتج). أدى هذا إلى حقيقة أن استبدال الأجزاء في handler.postDelayed()
تنفيذه غالبًا في وقت handler.postDelayed()
جدًا أو متأخر جدًا ، مما أدى إلى تفاقم المشكلة السابقة فقط.
وكان آخر ما يميز هو أنه خلال الرسوم المتحركة ، يمكن للمستخدم ببساطة الانتقال إلى صفحة أخرى ومشاهدة شاشتين توأمين ، وبعد ذلك سحبها التطبيق أيضًا على الشاشة المطلوبة.
التحف المثيرة للاهتمام لهذا النهج (الرسوم المتحركة - 2.7 ميغابايت) هذا الوضع لم يناسبني ، وبدأت ، مليئة بالغضب الصالح ، في البحث عن حل آخر.
محاولة PageTransformer
لم تكن هناك إجابات على الإنترنت ، وفكرت: كيف يمكن تحسين هذا الانتقال. همس لي شيء في القشرة الفرعية للوعي: "استخدم PageTransformer
، Luke." كانت الفكرة واعدة بالنسبة لي وقررت الاستماع.
تتمثل الفكرة في جعل PageTransformer
، والتي ، على عكس Android SET ، لن تتطلب تكرارًا setTransitionName(transitionName)
من setTransitionName(transitionName)
و FragmentTransaction.addSharedElement(sharedElement,name)
على جانبي الانتقال. سينقل العناصر بعد التمرير ويكون له واجهة بسيطة للنموذج:
public void addSharedTransition(int fromViewId, int toViewId)
ننتقل إلى التطوير. addSharedTransition(fromId, toId)
البيانات من طريقة addSharedTransition(fromId, toId)
إلى Set
from Pair
وأحصل عليها بطريقة PageTransfomer
public void transformPage(@NonNull View page, float position)
في الداخل ، سأستعرض جميع أزواج View
المحفوظة ، والتي أحتاجها لعمل رسم متحرك. وسأحاول تصفيتها حتى يتم تحريك العناصر المرئية فقط.
أولاً ، دعونا نتحقق مما إذا كانت العناصر التي تحتاج إلى رسوم متحركة قد تم إنشاؤها. نحن لسنا مختارين ، وإذا View
يتم إنشاء العرض قبل بدء الرسوم المتحركة ، فلن نكسر الرسوم المتحركة بأكملها (مثل انتقال العنصر المشترك ) ، ولكننا نستلمها عندما يتم إنشاء العنصر.
for (Pair<Integer,Integer> idPair : sharedElementIds) { Integer fromViewId = idPair.first; Integer toViewId = idPair.second; View fromView = activity.findViewById(fromViewId); View toView = activity.findViewById(toViewId); if (fromView != null && toView != null) {
أجد الصفحات التي تحدث فيها الحركة (كيف يمكنني تحديد رقم الصفحة أدناه).
View fromPage = pages.get(fromPageNumber); View toPage = pages.get(toPageNumber);
إذا تم إنشاء كلتا الصفحتين بالفعل ، فأنا أبحث عن زوج من View
عليهما ، وهو ما أحتاج إلى تحريكه.
If (fromPage != null && toPage != null) { fromView = fromPage.findViewById(fromViewId); toView = toPage.findViewById(toViewId);
في هذه المرحلة ، اخترنا طريقة العرض ، والتي تقع على الصفحات التي ينتقل فيها المستخدم.
لقد حان الوقت للحصول على الكثير من المتغيرات. أحسب النقاط المرجعية:
في المقتطف الأخير ، قمت بتعيين slideToTheRight
، وسيكون بالفعل مفيدًا لي في هذا. تعتمد علامة تسجيل الدخول على ذلك ، والذي يحدد أن View
سوف ينتقل إلى مكانه أو في مكان ما خارج الشاشة.
float pageWidth = getScreenWidth(); float sign = slideToTheRight ? 1 : -1; float translationY = (deltaY + deltaHeight / 2) * sign * (-position); float translationX = (deltaX + sign * pageWidth + deltaWidth / 2) * sign * (-position);
ومن المثير للاهتمام ، أن صيغ الإزاحة لـ X
و Y
لكل من View
، على صفحة البداية والصفحة الناتجة ، تبين أنها واحدة ، على الرغم من الإزاحات الأولية المختلفة.
ولكن مع النطاق ، لسوء الحظ ، لن تنجح هذه الخدعة - عليك التفكير فيما إذا كانت View
هذه View
نقطة البداية أو النهاية للرسوم المتحركة.
قد يكون ذلك بمثابة مفاجأة لشخص ما ، ولكن يتم transformPage(@NonNull View page, float position)
عدة مرات: لكل صفحة مخبأة (يمكن تخصيص حجم ذاكرة التخزين المؤقت). ومن أجل عدم إعادة رسم العرض المتحرك عدة مرات ، لكل مكالمة transformPage()
، نغير فقط تلك الموجودة في page
الحالية.
وضعنا موضع وحجم العناصر المتحركة حدد الصفحات لرسم الرسوم المتحركة
لا يتعجل برنامج ViewPager
مشاركة المعلومات بين الصفحات التي يتم التمرير فيها. كما وعدت ، الآن سوف أخبرك كيف نحصل على هذه المعلومات. في PageTransformer
بنا PageTransformer
نقوم بتطبيق واجهة ViewPager.OnPageChangeListener
أخرى. بعد دراسة إخراج onPageScrolled()
خلال System.out.println()
توصلت إلى الصيغة التالية:
public void onPageScrolled( int position, float positionOffset, int positionOffsetPixels ) { Set<Integer> visiblePages = new HashSet<>(); visiblePages.add(position); visiblePages.add(positionOffset >= 0 ? position + 1 : position - 1); visiblePages.remove(fromPageNumber); toPageNumber = visiblePages.iterator().next(); if (pages == null || toPageNumber >= pages.size()) toPageNumber = null; } public void onPageSelected(int position) { this.position = position; } public void onPageScrollStateChanged(int state) { if (state == SCROLL_STATE_IDLE) {
هذا كل شيء. لقد فعلنا ذلك! الرسوم المتحركة تراقب إيماءات المستخدم. لماذا تختار بين الانتقال السريع وانتقال العناصر المشتركة ، عندما يمكنك ترك كل شيء.
أثناء كتابة هذا المقال ، أضفت تأثير اختفاء العناصر الثابتة - فهو لا يزال خامًا للغاية ، لذلك لم تتم إضافته إلى المكتبة.
تعرف على ما حدث في النهاية (الرسوم المتحركة - 2.4 ميغابايت) شفرة المصدر بالكامل | /** |
| * PageTransformer that allows you to do shared element transitions between pages in ViewPager. |
| * It requires view pager sides match screen sides to function properly. I.e. ViewPager page width |
| * must be equal to screen width. <br/> |
| * Usage:<br/> |
| * <code> |
| * sharedElementPageTransformer.addSharedTransition(R.id.FirstPageTextView, R.id.SecondPageTextView)</code> |
| * </code> |
| * |
| * |
| */ |
| public class SharedElementPageTransformer implements ViewPager.PageTransformer, ViewPager.OnPageChangeListener { |
| /** Android need the correction while view scaling for some reason*/ |
| private static float MAGICAL_ANDROID_RENDERING_SCALE = 1; |
| // private static float MAGICAL_ANDROID_RENDERING_SCALE = 0.995f; |
| |
| // External variables |
| |
| private final Activity activity; |
| List<Fragment> fragments; |
| private Set<Pair<Integer,Integer>> sharedElementIds = new HashSet<>(); |
| |
| |
| |
| //Internal variables |
| |
| private List<View> pages; |
| private Map<View, Integer> pageToNumber = new HashMap<>(); |
| |
| private Integer fromPageNumber = 0; |
| private Integer toPageNumber; |
| |
| /** current view pager position */ |
| private int position; |
| |
| /** |
| * @param activity activity that hosts view pager |
| * @param fragments fragment that are in view pager in the SAME ORDER |
| */ |
| public SharedElementPageTransformer(Activity activity, List<Fragment> fragments) { |
| this.activity = activity; |
| this.fragments = fragments; |
| } |
| |
| |
| @Override |
| public void transformPage(@NonNull View page, float position) { |
| updatePageCache(); |
| if (fromPageNumber == null || toPageNumber == null) return; |
| |
| for (Pair<Integer,Integer> idPair : sharedElementIds) { |
| Integer fromViewId = idPair.first; |
| Integer toViewId = idPair.second; |
| |
| View fromView = activity.findViewById(fromViewId); |
| View toView = activity.findViewById(toViewId); |
| |
| if (fromView != null && toView != null) { |
| //Looking if current Shared element transition matches visible pages |
| |
| View fromPage = pages.get(fromPageNumber); |
| View toPage = pages.get(toPageNumber); |
| |
| if (fromPage != null && toPage != null) { |
| fromView = fromPage.findViewById(fromViewId); |
| toView = toPage.findViewById(toViewId); |
| |
| |
| // if both views are on pages user drag between apply transformation |
| if ( |
| fromView != null |
| && toView != null |
| ) { |
| // saving shared element position on the screen |
| float fromX = fromView.getX() - fromView.getTranslationX(); |
| float fromY = fromView.getY() - fromView.getTranslationY(); |
| float toX = toView.getX() - toView.getTranslationX(); |
| float toY = toView.getY() - toView.getTranslationY(); |
| float deltaX = toX - fromX; |
| float deltaY = toY - fromY; |
| |
| // scaling |
| float fromWidth = fromView.getWidth(); |
| float fromHeight = fromView.getHeight(); |
| float toWidth = toView.getWidth(); |
| float toHeight = toView.getHeight(); |
| float deltaWidth = toWidth - fromWidth; |
| float deltaHeight = toHeight - fromHeight; |
| |
| |
| int fromId = fromView.getId(); |
| int toId = toView.getId(); |
| |
| boolean slideToTheRight = toPageNumber > fromPageNumber; |
| |
| if (position <= -1) { |
| |
| } else if (position < 1) { |
| |
| float pageWidth = getSceenWidth(); |
| float sign = slideToTheRight ? 1 : -1; |
| |
| float translationY = (deltaY + deltaHeight / 2) * sign * (-position); |
| float translationX = (deltaX + sign * pageWidth + deltaWidth / 2) * sign * (-position); |
| |
| if (page.findViewById(fromId) != null) { |
| fromView.setTranslationX(translationX); |
| fromView.setTranslationY(translationY); |
| |
| float scaleX = (fromWidth == 0) ? 1 : (fromWidth + deltaWidth * sign * (-position)) / fromWidth; |
| float scaleY = (fromHeight == 0) ? 1 : (fromHeight + deltaHeight * sign * (-position)) / fromHeight; |
| |
| fromView.setScaleX(scaleX); |
| fromView.setScaleY(scaleY * MAGICAL_ANDROID_RENDERING_SCALE); |
| } |
| if (page.findViewById(toId) != null) { |
| |
| toView.setTranslationX(translationX); |
| toView.setTranslationY(translationY); |
| float scaleX = (toWidth == 0) ? 1 : (toWidth + deltaWidth * sign * (-position)) / toWidth; |
| float scaleY = (toHeight == 0) ? 1 :(toHeight + deltaHeight * sign * (-position)) / toHeight; |
| |
| toView.setScaleX(scaleX); |
| toView.setScaleY(scaleY); |
| } |
| |
| |
| } else { |
| } |
| |
| } |
| } |
| } |
| } |
| } |
| |
| private float getSceenWidth() { |
| Point outSize = new Point(); |
| activity.getWindowManager().getDefaultDisplay().getSize(outSize); |
| return outSize.x; |
| } |
| |
| /** |
| * Creating page cache array to determine if shared element on |
| * currently visible page |
| */ |
| private void updatePageCache() { |
| pages = new ArrayList<>(); |
| |
| for (int i = 0; i < fragments.size(); i++) { |
| View pageView = fragments.get(i).getView(); |
| pages.add(pageView); |
| pageToNumber.put(pageView, i); |
| |
| } |
| } |
| |
| |
| @Override |
| public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { |
| Set<Integer> visiblePages = new HashSet<>(); |
| |
| visiblePages.add(position); |
| visiblePages.add(positionOffset >= 0 ? position + 1 : position - 1); |
| visiblePages.remove(fromPageNumber); |
| |
| toPageNumber = visiblePages.iterator().next(); |
| |
| if (pages == null || toPageNumber >= pages.size()) toPageNumber = null; |
| } |
| |
| |
| @Override |
| public void onPageSelected(int position) { |
| this.position = position; |
| } |
| |
| @Override |
| public void onPageScrollStateChanged(int state) { |
| if (state == SCROLL_STATE_IDLE) { |
| fromPageNumber = position; |
| resetViewPositions(); |
| } |
| |
| } |
| |
| private void resetViewPositions() { |
| for (Pair<Integer, Integer> idPair : sharedElementIds) { |
| View sharedElement = activity.findViewById(idPair.first); |
| if(sharedElement != null) { |
| sharedElement.setTranslationX(0); |
| sharedElement.setTranslationY(0); |
| sharedElement.setScaleX(1); |
| sharedElement.setScaleY(1); |
| } |
| sharedElement = activity.findViewById(idPair.second); |
| if(sharedElement != null) { |
| |
| sharedElement.setTranslationX(0); |
| sharedElement.setTranslationY(0); |
| sharedElement.setScaleX(1); |
| sharedElement.setScaleY(1); |
| } |
| } |
| |
| } |
| |
| /** |
| * Set up shared element transition from element with <code>fromViewId</code> to |
| * element with <code>toViewId</code>. Note that you can setup each transition |
| * direction separately. e.g. <br/> |
| * <code>addSharedTransition(R.id.FirstPageTextView, R.id.SecondPageTextView)</code><br/> |
| * and<br/> |
| * <code>addSharedTransition(R.id.SecondPageTextView, R.id.FirstPageTextView)</code><br/> |
| * are different. |
| * @param fromViewId |
| * @param toViewId |
| */ |
| public void addSharedTransition(int fromViewId, int toViewId) { |
| addSharedTransition(fromViewId, toViewId, false); |
| } |
| |
| /** |
| * Set up shared element transition from element with <code>fromViewId</code> to |
| * element with <code>toViewId</code>. Note that you can setup each transition |
| * direction separately. e.g. <br/> |
| * <code>addSharedTransition(R.id.FirstPageTextView, R.id.SecondPageTextView)</code><br/> |
| * and<br/> |
| * <code>addSharedTransition(R.id.SecondPageTextView, R.id.FirstPageTextView)</code><br/> |
| * are different. |
| * @param fromViewId |
| * @param toViewId |
| * @param bothDirections to include backward transition from toViewId to fromViewId aswell |
| */ |
| public void addSharedTransition(int fromViewId, int toViewId, boolean bothDirections) { |
| sharedElementIds.add(new Pair<>(fromViewId, toViewId)); |
| if(bothDirections) { |
| sharedElementIds.add(new Pair<>(toViewId, fromViewId)); |
| } |
| } |
| /** |
| * In case there is "ladder" appears between while transition. |
| * You may try to tune that magical scale to get rid of it. |
| * @param magicalAndroidRenderingScale float between 0 and infinity. Typically very close to 1.0 |
| */ |
| public static void setMagicalAndroidRenderingScale(float magicalAndroidRenderingScale) { |
| MAGICAL_ANDROID_RENDERING_SCALE = magicalAndroidRenderingScale; |
| } |
| } |
كيف يبدو العمل مع المكتبة؟
تحول التكوين موجزة جدا.
الإعداد الكامل لمثالنا يشبه هذا ArrayList<Fragment> fragments = new ArrayList<>(); fragments.add(hello_fragment); fragments.add(small_picture_fragment); fragments.add(big_picture_fragment); SharedElementPageTransformer transformer = new SharedElementPageTransformer(this, fragments); transformer.addSharedTransition(R.id.smallPic_image_cat2, R.id.bigPic_image_cat, true); transformer.addSharedTransition(R.id.smallPic_text_label3, R.id.bigPic_text_label, true); transformer.addSharedTransition(R.id.hello_text, R.id.smallPic_text_label3, true); viewPager.setPageTransformer(false, transformer); viewPager.addOnPageChangeListener(transformer);
قد يبدو onClick
، بما في ذلك جميع الانتقالات ، كما يلي:
smallCatImageView.setOnClickListener( v -> activity.viewPager.setCurrentItem(2) );
حتى لا تختفي الشفرة ، أضع المكتبة في مستودع JCenter وعلى GitHub . لذلك تواصلت مع عالم المصادر المفتوحة. يمكنك تجربته في مشروعك ببساطة عن طريق الإضافة
dependencies {
جميع المصادر متوفرة على جيثب
استنتاج
حتى إذا كانت الإنترنت لا تعرف الإجابة ، فإن هذا لا يعني أنها ليست كذلك. ابحث عن الحلول ، حاول حتى تعمل. ربما تكون أول من وصل إلى أسفل هذا الأمر وشاركه مع المجتمع.