CoordinatorLayout’u MotionLayout ile harmanlamak 👨‍🍳

Furkan Paşaoğlu
DigiGeek
Published in
4 min readFeb 18, 2021
Biraz CoordinatorLayout, biraz MotionLayout ve iyi olan her şey…

Merhabalar, bugünki yazımızda Android geliştiriciler olarak çoğu kez tek başına kullandığımız iki layout’u aynı tasarımda kullanmayı öğreneceğiz. CoordinatorLayout’un scrollFlag özelliğinden yararlanacak, MotionLayout’un animasyon geçişleri ile uygulamaya ayrı bir hava katacağız. Sonucunda aşağıdaki gibi bir sonuç elde edeceğiz 👇

Bu yazımda iki layout sınıfının ne olduğundan bahsetmeyeceğim. Yazının başlığında belirtildiği üzere burada işimiz bu layoutları harmanlamak 👨‍🍳

Bkz: CoordinatorLayout 👈 👉 MotionLayout

Haydi Kod Zamanı 🕺

Component Tree inceleyerek başlayalım.

CoordinatorLayout’un parent view olduğu, AppBarLayout ve NestedScrollView ‘in ise child view olduğu bir yapı oluşturuldu.

CoordinatorLayout, NestedScrollView içerisinde yapılan scroll işleminin haberini AppBarLayout’a iletir. AppBarLayout da scrollFlagler aracılığıyla layout tasarımına ayar çeker.

Activity_main.xml kodlarının tamamını paylaşıyorum ⬇️ ama kodumuzu bölerek inceleyecek ve nasıl bir yapı oluşturduk birlikte anlayacağız 💪

<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="@dimen/app_bar_height"
android:theme="@style/AppTheme.AppBarOverlay">

CoordinatorLayout altındaki AppBarLayout’u inceleyerek başlayalım. app_bar_height = 200 dp olarak belirledim. Bu bilgi dimen.xml içerisinde yer alıyor. Bu layout, uygulama açılış ekranında 200 dp yüksekliğinde bir appBarLayout çizdirilmesini ve scroll işlemi sırasında bu layout’un yukarı doğru küçülmesini sağlayacaktır.

<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="@dimen/layout_min_height"
app:layoutDescription="@xml/activity_main_scene"
app:layout_scrollFlags="scroll|exitUntilCollapsed">

<ImageView
android:id="@+id/background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:contentDescription="@string/background_desc"
app:srcCompat="@drawable/digital" />

<ImageView
android:id="@+id/icon_digigeek"
android:contentDescription="@string/icon_digigeek_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_digigeek" />

<TextView
android:id="@+id/textview_digigeek"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.0"
android:contentDescription="@string/digigeek"
android:text="@string/digigeek"
android:textSize="@dimen/text_size_medium" />

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

Sırada MotionLayout var. Burada minHeight attribute önemli, minimum height’ı belirliyoruz. AppBarLayout’u sınırlıyoruz ve belirlediğimiz minHeight’a kadar collapse etmesini(yukarı doğru küçülmesini) ve daha fazla küçülememesini sağlıyoruz. layout_min_height = 80dp olarak belirledim. AppBarLayout height’ı 200 dp idi. Bu da demek oluyor ki 200dp ile çizdirilen tasarım, scroll edildikçe 80 dp’e kadar collapse edilebilecek.

layoutDescription alanı bir diğer önemli attribute. Bu da MotionLayout için MotionScene tanımladığımız alan. Bu dosyaya activity_main_scene içerisinde erişebileceğini ve bu dosyada yazan kod parçacıklarına göre animasyon hünerlerini gösterebileceğini belirtiriz.

ScrollFlags , CoordinatorLayout tarafından bize sağlanan attribute, scroll sonrası MotionLayout’un nasıl davranması gerektiğini belirtiyor.

Scroll : Text içerisinde kaydırma yapılması durumunda MotionLayout’un da aynı yönde kaydırılmasını sağlar. Bu flag ile ekran kaydırma özelliği aktif oluyor diyebiliriz.

ExitUntilCollapsed : NestedScrollView aşağı doğru kaydırıldığında MotionLayout ne kadar collapse edilebiliyorsa o kadar et. MotionLayout içerisinde minHeight vermemizdeki amaç da bu. minHeight’tan sonrasını collapse edemiyor yani yukarı doğru küçülemiyor. Ekranda DigiGeek yazan toolbar sabit kalıyor.

ScrollFlags özellikleri aralarındaki farkı detaylı incelemek için 👉 tıkla 👈

<androidx.core.widget.NestedScrollView
android:id="@+id/nested_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">

<TextView
android:id="@+id/textview_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/long_text" />


</androidx.core.widget.NestedScrollView>

NestedScrollView bildiğiniz gibi ama çok önemli bir fark var burada. Scroll edildiğinde AppBarLayout’un haberdar olmasını sağlamak için layout_behaviour ekliyoruz ve parametre olarak “com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior” veriyoruz.

Evet, activity_main.xml içerisindeki tanımları birlikte inceledik. Şimdi MotionLayout içerisinde app:layoutDescription alanına tanımladığımız ve ekranda animasyon geçişlerini yönettiğimiz activity_main_scene.xml kodlarını inceleyelim

2 adet ConstraintSet’imiz var , @id/start uygulamanın açılışını , @id/end ise kaydırma yapıldıkça nasıl bir kapanış olacağını belirtiyor.

<Transitions> içerisinde <KeyAttribute> ve <KeyPosition> larımız var. Burada framePosition vererek ek birkaç özellik ekledim. Örneğin

  • DigiGeek Icon’un Y eksenini %60 oranında arttırmak, böylece havaya yükseliyormuş izlenimi vermek.
  • Arkaplanda yer alan resmin alpha değerini 0.0 vererek, animasyonun 100.Frame’i esnasında arkaplan resmini invisible yapmak.
  • DigiGeek Text’ini 85.frame’den sonra visible olmasını ve X ekseni etrafında 2 defa dönmesini sağlamak…..

Tamam, süper. CoordinatorLayout ve MotionLayout’u harmanlayarak hayalimizdeki tasarımı kodlayabildik. Şimdi kodumuzu çalıştırıp test etme vakti...

Evet, uygulama build oldu. Test ediyoruz ve görüyoruz ki text scroll edilmesi AppBarLayout’un collapse edilmesini sağladı ama yazmış olduğumuz animasyonların hiçbiri çalışmadı 🤔

Kodlarımızı tekrardan inceliyor ve fark ediyoruz ki çalışmaması çok normal. Çünkü Scroll işleminin bilgisi NestedScrollView ve AppBarLayout arasında kalmakta. MotionLayout’un bu işlemden haberi olmamakta. MainActivity içerisinde yazacağımız fonksiyon ile motionlayout’u bu bilgiden mahrum bırakmayacağız.

AppBarLayout için yazmış olduğumuz listener, scroll anında position bilgisini motinLayout.progress’e eşitlemektedir. Böylece MotionLayout, scroll bilgisini elde edecek ve animasyon başarılı bir şekilde çalışacaktır.

Tekrardan çalıştırıyor, test ediyor ve başarılı şekilde çalıştığını görüyoruz 🎉

Umarım bu tasarım sizin için faydalı olmuştur. Bu yazıda MotionLayout’u CoordinatorLayout ile harmanladık. Siz ihtiyacınıza göre farklı tarifler uygulayabilirsiniz. MotionLayout ile yapabilecekleriniz sınırı yok, asıl olay hayal gücünüzde ⚡️

Sağlıcakla kalın…

--

--