فعال و غیرفعال کردن View در اندروید
بعضی مواقع پیش میاد که ما میخوایم بخشی از طراحی خودمون رو غیرفعال کنیم.
فرضا اگه کاربر فلان کار رو انجام نداده باشه، یه بخشی از اپلیکیشن رو نتونه ازش استفاده کنه.
اینجور مواقع اکثرا میان اون بخش هایی که غیرفعال هستن رو خاکستری میکنن که کابر متوجه بشه که این بخش در دسترس نیستش.
برای اینکار برنامه نویس ها میان 2 طرح مجزا رو طراحی میکنن.
یکی برای حالت فعال و یکی هم برای حالت غیرفعال!
خب عملا این روش بدترین روش هستش?
چون اگه بخوای تغییری توی طرح ایجاد بکنی باید برای هر 2 حالت طرحت رو تغییر بدی?
خب راه حل چیه؟ پس باید چیکار کرد؟
راه حل چیزیه که میخوام تویه این پست بگم?
برای اینکه بهتر منظورم رو درک کنی پشنهاد میکنم دمو رو ببینی.
دمو نتیجه انجام شده
فعال و غیرفعال کردن Viewها
توی این پست میخوام یک Custom View (ویو سفارشی) درست کنم که هر ویوای که داخل اون قرار بدین قابلیت غیرفعال کردن رو میتونه بگیره.
برای ساختن این Custom view از Constraint layout استفاده کردم.
همونطور که میدونی ConstraintLayout یکی از لایه های اندروید هستش که میشه باهاش طراحی رابط کاربری انجام داد.
ساخت ویو سفارشی از ConstraintLayout
برای ساختن این ویو سفارشی همونطور که گفتم از Constraint Layout استفاده کردم.
من اسم این ویو رو ConstraintLayoutWithDisableSupport گذاشتم.
یعنی ConstraintLayoutای که حالت غیرفعال رو پشتیبانی میکنه?.
اول از همه از Point استفاده کردم که بتونم به واسطه اون، نقاط رنگی مختلف رو روی ویوهای خودم اعمال کنم.
بعد از اون رنگ خاکستری رو به صورت آرایه درست کردم و در این نقاط اعمال کردم.
کدی که نوشتن به شکل زیر هستش
private val paint = Paint() val cm = ColorMatrix() cm.set( floatArrayOf( 0.33f, 0.33f, 0.33f, 0f, 0f, 0.33f, 0.33f, 0.33f, 0f, 0f, 0.33f, 0.33f, 0.33f, 0f, 0f, 0f, 0f, 0f, 1f, 0f ) ) paint.colorFilter = ColorMatrixColorFilter(cm)
البته این بخشی از کد هستش که در ادامه کدنهایی رو هم قرار میدم.
توضیحاتی در مورد ساختار کد
بر اساس درک من از پردازش تصویر، در حالت ایده آل ما باید بتونیم هر رنگ RGB رو با یک ماتریس ضرب کنیم و در نتیجه رنگی به رنگ خاکستری بدست بیاریم.
سپس سعی کردم API مشابهی رو توی Android و ColorMatrix پیدا کنم که همراه با برخی از سفارشی سازی ها مواردی که مدنظرم بود رو میتونستم پیاده سازی کنم.
من تصمیم گرفتم یک ماتریس سفارشی رو با مقادیر مساوی قرمز، سبز و آبی آزمایش کنم.
از اون موارد واسه فیلترهای رنگی برای CustomView استفاده کردم که اجازه میداد رنگ های ویوها رو به خاکستری تغییر بدم.
نتیجه توضیحات بالا کد زیر شد، چیزی که میتونستم باهاش ویوهام رو تغییر رنگ بدم.
private val paint = Paint() val cm = ColorMatrix() cm.set( floatArrayOf( 0.33f, 0.33f, 0.33f, 0f, 0f, 0.33f, 0.33f, 0.33f, 0f, 0f, 0.33f, 0.33f, 0.33f, 0f, 0f, 0f, 0f, 0f, 1f, 0f ) ) paint.colorFilter = ColorMatrixColorFilter(cm)
از نقاط بالا توی Canvas با استفاده از متدهای dispatchDraw() و draw() میتونیم رنگ خاکستری رو اعمال کنیم.
به این صورت من از کد بالا توی ConstraintLayout استفاده کردم.
کدنهایی مربوط به Constraint Layout سفارشی
import android.content.Context import android.graphics.Canvas import android.graphics.ColorMatrix import android.graphics.ColorMatrixColorFilter import android.graphics.Paint import android.util.AttributeSet import androidx.constraintlayout.widget.ConstraintLayout class ConstraintLayoutWithDisableSupport @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr) { var disabled = false set(value) { field = value requestLayout() } private val paint = Paint() init { val cm = ColorMatrix() cm.set( floatArrayOf( 0.33f, 0.33f, 0.33f, 0f, 0f, 0.33f, 0.33f, 0.33f, 0f, 0f, 0.33f, 0.33f, 0.33f, 0f, 0f, 0f, 0f, 0f, 1f, 0f ) ) paint.colorFilter = ColorMatrixColorFilter(cm) } override fun dispatchDraw(canvas: Canvas?) { if (disabled) { canvas?.saveLayer(null, paint) } super.dispatchDraw(canvas) if (disabled) { canvas?.restore() } } override fun draw(canvas: Canvas?) { if (disabled) { canvas?.saveLayer(null, paint) } super.draw(canvas) if (disabled) { canvas?.restore() } } }
استفاده از این ویو سفارشی
استفاده کردن از این ویو فوقالعاده راحته.
فقط کافیه ویوهایی که میخوای فعال و غیرفعال بشن رو داخل این لایه قرار بدی.
این لایه هم از نظر ساختار درست مثل ConstraintLayout هستش و هیچ فرقی نمیکنه.
تمامی آپشن ها و امکانات اون رو داره.
من میخوام طرحی که توی دمو نشون دادم رو درست کنم.
برای اینکار از 2 تا لایه استفاده کردم.
لایه اصلی که در واقع مربوط به صفحه کلی میشه که Switch مربوط به غیرفعال کردن رو داره.
لایه دوم هم مواردی که میخوام فعال و غیرفعال بشن رو داخل اون قرار دادم.
کدهای مربوط به لایه اصلی
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".disable_constraintlayout.DisableConstraintPage"> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/disableConstraintPage_switchLay" android:layout_width="0dp" android:layout_height="70dp" android:background="@color/aquaBlue" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"> <TextView android:id="@+id/disableConstraintPage_switchTxt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@font/iran_sans" android:text="فعال / غیرفعال کردن لایه ها" android:layout_marginRight="20dp" android:textColor="@color/bgLight" android:textSize="12sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.SwitchCompat android:id="@+id/disableConstraintPage_switch" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="10dp" android:checked="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/disableConstraintPage_switchTxt" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> <include android:id="@+id/sample_view" layout="@layout/disable_constraintlayout_items" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/disableConstraintPage_switchLay" /> </androidx.constraintlayout.widget.ConstraintLayout>
کدهای مربوط به ویوهای فعال و غیرفعال شده
<?xml version="1.0" encoding="utf-8"?> <in.nouri.myinstagramtutorials.disable_constraintlayout.ConstraintLayoutWithDisableSupport xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="20dp"> <ImageView android:id="@+id/iv_image" android:layout_width="200dp" android:layout_height="200dp" android:src="@drawable/my" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:ignore="ContentDescription" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="15dp" android:fontFamily="@font/iran_sans" android:text="محمد نوری" android:textColor="@color/teal_700" android:textSize="26sp" app:layout_constraintEnd_toEndOf="@+id/iv_image" app:layout_constraintStart_toStartOf="@+id/iv_image" app:layout_constraintTop_toBottomOf="@+id/iv_image" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/tv_site" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="www.nouri.academy" android:textColor="@color/pink" android:textSize="16sp" app:layout_constraintEnd_toEndOf="@+id/iv_image" app:layout_constraintStart_toStartOf="@+id/iv_image" app:layout_constraintTop_toBottomOf="@id/tv_title" /> <com.google.android.material.card.MaterialCardView android:id="@+id/item1" android:layout_width="0dp" android:layout_height="60dp" android:layout_marginTop="10dp" app:cardBackgroundColor="@color/itemColor2" app:cardCornerRadius="10dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv_site" app:strokeColor="@color/itemColorStroke" app:strokeWidth="1dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:fontFamily="@font/iran_sans" android:text="آیتم اول" android:textColor="@color/bgLight" android:textSize="16sp" /> </com.google.android.material.card.MaterialCardView> <com.google.android.material.card.MaterialCardView android:id="@+id/item2" android:layout_width="0dp" android:layout_height="60dp" android:layout_marginTop="10dp" app:cardBackgroundColor="@color/itemColor2" app:cardCornerRadius="10dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/item1" app:strokeColor="@color/itemColorStroke" app:strokeWidth="1dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:fontFamily="@font/iran_sans" android:text="آیتم دوم" android:textColor="@color/bgLight" android:textSize="16sp" /> </com.google.android.material.card.MaterialCardView> </in.nouri.myinstagramtutorials.disable_constraintlayout.ConstraintLayoutWithDisableSupport>
نتیجه نهایی مثل عکس زیر میشه
من قصد داشتم کل لایه رو غیرفعال کنم، برای همین تمامی ویوها رو داخل ConstraintLayoutWithDisableSupport نوشتم.
حالا شما با توجه به طرح خودت میتونی اون ویوها رو داخل این لایه قرار بدی.
کدهای مربوط به کاتلین
برای اینکه بتونی ویوها رو به صورت داینامیک فعال و غیرفعال باید به صورت کاتلین (یا جاوا) اون رو هندل کنی.
من برای اینکار کد زیر رو نوشتم
class DisableConstraintPage : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_disable_constraint_page) disableConstraintPage_switch.setOnCheckedChangeListener { _, _ -> if (disableConstraintPage_switch.isChecked) { setSampleViewToEnabled() } else { setSampleViewToDisabled() } } } private fun setSampleViewToDisabled() { (sample_view as ConstraintLayoutWithDisableSupport).disabled = true } private fun setSampleViewToEnabled() { (sample_view as ConstraintLayoutWithDisableSupport).disabled = false } }
این کد 2 تا متد داره.
- setSampleViewToDisabled : برای غیرفعال کردن ویوها
- setSampleViewToEnabled : برای فعال کردن ویوها
برای فعال یا غیرفعال کردن لایه فقط کافیه که ID لایه رو بنویسی و بعدش از disabled استفاده کنی.
درست مثل کاری که من توی این 2 تا متد انجام دادم.
بعد از اجرا کردن اپلیکیشن و زدن دکمه غیرفعال کردن، ویوهات مثل عکس زیر خاکستری میشن.
امیدوارم که از این آموزش هم لذت ببری و از نهایت استفاده رو بکنی❤