چرخ فلک با MotionLayout

Carousel یک شی کمکی حرکتی برای ساخت نماهای چرخ و فلک سفارشی است که لیستی از عناصری را که کاربر می تواند از آنها عبور کند نشان می دهد. در مقایسه با روش‌های دیگر برای پیاده‌سازی چنین نماهایی، این کمک‌کننده به شما امکان می‌دهد تا با استفاده از MotionLayout ، به سرعت تغییرات پیچیده و حرکتی را برای Carousel خود ایجاد کنید.

ویجت Carousel از لیست‌هایی با شروع و پایان و همچنین لیست‌های حلقه‌ای گرد پشتیبانی می‌کند.

Carousel with MotionLayout چگونه کار می کند

فرض کنید می خواهید یک نمای افقی Carousel فلک بسازید، با آیتم مرکزی بزرگ شده:

این طرح اولیه شامل چندین نمای است که آیتم های Carousel را نشان می دهد:

یک MotionLayout با سه حالت زیر ایجاد کنید و به آنها شناسه بدهید:

  • قبلی
  • شروع کنید
  • بعدی

اگر حالت شروع با چیدمان پایه مطابقت داشته باشد، در حالت قبلی و بعدی موارد Carousel به ترتیب یک به چپ و راست منتقل می شوند.

به عنوان مثال، پنج نما در شکل 3 را در نظر بگیرید و فرض کنید که در حالت شروع ، نماهای B، C و D قابل مشاهده هستند و A و E خارج از صفحه نمایش هستند. حالت قبلی را طوری تنظیم کنید که موقعیت های A، B، C و D در جایی باشد که B، C، D و E قرار دارند و نماها از چپ به راست حرکت می کنند. در حالت بعدی باید برعکس اتفاق بیفتد، با حرکت B، C، D و E به جایی که A، B، C و D قرار داشتند و نماها از راست به چپ حرکت کنند. این در شکل 4 نشان داده شده است:

بسیار مهم است که نماها دقیقاً به همان جایی ختم شوند که نماهای اصلی شروع می شوند. Carousel با انتقال نماهای واقعی به جایی که بودند، اما دوباره آنها را با محتوای منطبق جدید، توهم مجموعه بی نهایتی از عناصر را ایجاد می کند. نمودار زیر این مکانیسم را نشان می دهد. به مقادیر "اقلام #" توجه کنید):

انتقال ها

با این سه مجموعه محدودیت که در فایل صحنه حرکت شما تعریف شده است، دو انتقال - جلو و عقب - بین حالت شروع و بعدی و حالت شروع و قبلی ایجاد کنید. همانطور که در مثال زیر نشان داده شده است، یک کنترل کننده OnSwipe اضافه کنید تا انتقالات را در پاسخ به یک حرکت فعال کند:

    <Transition
        motion:constraintSetStart="@id/start"
        motion:constraintSetEnd="@+id/next"
        motion:duration="1000"
        android:id="@+id/forward">
        <OnSwipe
            motion:dragDirection="dragLeft"
            motion:touchAnchorSide="left" />
    </Transition>

    <Transition
        motion:constraintSetStart="@+id/start"
        motion:constraintSetEnd="@+id/previous"
        android:id="@+id/backward">
        <OnSwipe
            motion:dragDirection="dragRight"
            motion:touchAnchorSide="right" />
    </Transition>

پس از ایجاد این صحنه حرکتی اولیه، یک Helper Carousel به چیدمان اضافه کنید و به نماها به همان ترتیبی که انیمیشن قبلی و بعدی خود را پیاده سازی می کنید ارجاع دهید.

ویژگی های زیر را برای Helper Carousel تنظیم کنید:

  • app:carousel_firstView : نمایی که اولین عنصر Carousel را نشان می دهد — در این مثال، C.
  • app:carousel_previousState : شناسه ConstraintSet حالت قبلی .
  • app:carousel_nextState : شناسه ConstraintSet حالت بعدی .
  • app:carousel_backwardTransition : شناسه Transition بین حالت شروع و قبلی اعمال می شود.
  • app:carousel_forwardTransition : شناسه Transition بین حالت شروع و بعدی اعمال می شود.

به عنوان مثال، شما چیزی شبیه به این را در فایل XML طرح بندی خود دارید:

    <androidx.constraintlayout.motion.widget.MotionLayout ... >

        <ImageView  android:id="@+id/imageView0" .. />
        <ImageView  android:id="@+id/imageView1" .. />
        <ImageView  android:id="@+id/imageView2" .. />
        <ImageView  android:id="@+id/imageView3" .. />
        <ImageView  android:id="@+id/imageView4" .. />

        <androidx.constraintlayout.helper.widget.Carousel
            android:id="@+id/carousel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:carousel_forwardTransition="@+id/forward"
            app:carousel_backwardTransition="@+id/backward"
            app:carousel_previousState="@+id/previous"
            app:carousel_nextState="@+id/next"
            app:carousel_infinite="true"
            app:carousel_firstView="@+id/imageView2"
            app:constraint_referenced_ids="imageView0,imageView1,imageView2,imageView3,imageView4" />

    </androidx.constraintlayout.motion.widget.MotionLayout>

یک آداپتور Carousel را در کد تنظیم کنید:

کاتلین

carousel.setAdapter(object : Carousel.Adapter {
            override fun count(): Int {
              // Return the number of items in the Carousel.
            }

            override fun populate(view: View, index: Int) {
                // Implement this to populate the view at the given index.
            }

            override fun onNewItem(index: Int) {
                // Called when an item is set.
            }
        })

جاوا

carousel.setAdapter(new Carousel.Adapter() {
            @Override
            public int count() {
                // Return the number of items in the Carousel.
            }

            @Override
            public void populate(View view, int index) {
                // Populate the view at the given index.
            }

            @Override
            public void onNewItem(int index) {
                 // Called when an item is set.
            }
        });

یادداشت های اضافی

بسته به مورد فعلی "انتخاب شده" در Carousel ، نماهایی که موارد قبل یا بعد از آن را نشان می دهند ممکن است برای محاسبه صحیح شروع و پایان Carousel پنهان شوند. Helper Carousel به طور خودکار این کار را انجام می دهد. به‌طور پیش‌فرض، آن نماها را در این شرایط به‌عنوان View.INVISIBLE علامت‌گذاری می‌کند، بنابراین طرح‌بندی کلی تغییر نمی‌کند.

یک حالت جایگزین در دسترس است که در آن راهنما Carousel به جای آن نماها را به عنوان View.GONE علامت گذاری می کند. می توانید این حالت را با استفاده از ویژگی زیر تنظیم کنید:

app:carousel_emptyViewsBehavior="gone"

نمونه ها

برای مثال های بیشتر با استفاده از کمک چرخ فلک، پروژه های نمونه در GitHub را ببینید.