bottom sheet در فرگمنت تمام صفحه

bottom sheet تمام صفحه در اندروید
اگر قصد ساخت bottom sheet با قابلیت تمام صفحه شدن را دارید، مقاله درستی را انتخاب کرده اید. bottom sheet در واقع یک view می باشد که به کمک آن می توان گزینه های انتخابی را نمایش داد. در آموزش امروز یاد می گیریم چگونه در برنامه یک bottom sheet زیبا ایجاد کنیم.
نتیجه نهایی به صورت زیر خواهد بود :
قدم اول : افزودن کتابخانه های لازم به پروژه
در فایل build.gradle موارد زیر را وارو می نماییم:
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'com.android.support:design:27.1.1' //enabling material designing implementation 'de.hdodenhof:circleimageview:3.0.1' // for circularImageView testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' }
در این پروژه از data binding یا محصورسازی داده ها استفاده می کنیم. برای درک بهتر data binding این مطلب را مطالعه نمایید. پس این مورد را نیز به build.gradle اضافه می کنیم :
dataBinding{ enabled true }
قدم دوم : ساخت layout مربوطه
برای ساخت bottomSheet باید layout ی مثل نمونه زیر بسازیم. که در آن bottomSheet به صورت pop up نمایش داده می شود.
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" android:orientation="vertical"> <com.google.android.material.appbar.AppBarLayout android:id="@+id/appBarLayout" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/colorAccent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <ImageButton android:id="@+id/cancelBtn" android:layout_width="?attr/actionBarSize" android:layout_height="?attr/actionBarSize" android:background="?attr/selectableItemBackgroundBorderless" android:src="@drawable/ic_cancel" android:tint="@android:color/white" /> <TextView android:id="@+id/nameToolbar" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginStart="15dp" android:layout_weight="1" android:text="Name" android:textAppearance="@style/TextAppearance.AppCompat.Title" android:textColor="@android:color/white" /> <ImageButton android:id="@+id/editBtn" android:layout_width="?attr/actionBarSize" android:layout_height="?attr/actionBarSize" android:background="?attr/selectableItemBackgroundBorderless" android:src="@drawable/ic_create" android:tint="@android:color/white" /> <ImageButton android:id="@+id/moreBtn" android:layout_width="?attr/actionBarSize" android:layout_height="?attr/actionBarSize" android:background="?attr/selectableItemBackgroundBorderless" android:src="@drawable/ic_more_vert" android:tint="@android:color/white" /> </LinearLayout> </com.google.android.material.appbar.AppBarLayout> <androidx.core.widget.NestedScrollView android:id="@+id/bottomSheet" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="15dp"> <LinearLayout android:id="@+id/profileLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="horizontal"> <ImageView android:id="@+id/userImage" android:layout_width="?attr/actionBarSize" android:layout_height="?attr/actionBarSize" android:src="@drawable/f_1" /> <TextView android:id="@+id/userName" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="15dp" android:layout_weight="1" android:text="user name" android:textAppearance="@style/TextAppearance.AppCompat.Subhead" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:orientation="horizontal"> <ImageButton android:layout_width="?attr/actionBarSize" android:layout_height="?attr/actionBarSize" android:background="?attr/selectableItemBackgroundBorderless" android:src="@drawable/ic_phone" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="10dp" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical"> <TextView android:id="@+id/number1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="(000) 000-000" android:textAppearance="@style/TextAppearance.AppCompat.Subhead" /> <TextView android:id="@+id/typeOfNumber1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Mobile" android:textAppearance="@style/TextAppearance.AppCompat.Small" /> </LinearLayout> <ImageButton android:layout_width="?attr/actionBarSize" android:layout_height="?attr/actionBarSize" android:background="?attr/selectableItemBackgroundBorderless" android:src="@drawable/ic_message_black_24dp" android:tint="@color/colorPrimary" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical"> <TextView android:id="@+id/number2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="(000) 000-000" android:textAppearance="@style/TextAppearance.AppCompat.Subhead" /> <TextView android:id="@+id/typeOfNumber2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Work" android:textAppearance="@style/TextAppearance.AppCompat.Small" /> </LinearLayout> <ImageButton android:layout_width="?attr/actionBarSize" android:layout_height="?attr/actionBarSize" android:background="?attr/selectableItemBackgroundBorderless" android:src="@drawable/ic_message_black_24dp" android:tint="@color/colorPrimary" /> </LinearLayout> </LinearLayout> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="15dp" android:layout_marginBottom="15dp" android:orientation="horizontal"> <View android:layout_width="?attr/actionBarSize" android:layout_height="0dp" /> <View android:layout_width="10dp" android:layout_height="0dp" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#e6e6e6" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <ImageButton android:layout_width="?attr/actionBarSize" android:layout_height="?attr/actionBarSize" android:background="?attr/selectableItemBackgroundBorderless" android:src="@drawable/ic_email" android:tint="@color/colorAccent" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="10dp" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:orientation="vertical"> <TextView android:id="@+id/email1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="email@email.com" android:textAppearance="@style/TextAppearance.AppCompat.Subhead" /> <TextView android:id="@+id/emailType1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Personal" android:textAppearance="@style/TextAppearance.AppCompat.Small" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:orientation="vertical"> <TextView android:id="@+id/email2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="email@email.com" android:textAppearance="@style/TextAppearance.AppCompat.Subhead" /> <TextView android:id="@+id/emailType2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Work" android:textAppearance="@style/TextAppearance.AppCompat.Small" /> </LinearLayout> </LinearLayout> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="15dp" android:layout_marginBottom="15dp" android:orientation="horizontal"> <View android:layout_width="?attr/actionBarSize" android:layout_height="0dp" /> <View android:layout_width="10dp" android:layout_height="0dp" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#e6e6e6" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <ImageButton android:layout_width="?attr/actionBarSize" android:layout_height="?attr/actionBarSize" android:background="?attr/selectableItemBackgroundBorderless" android:src="@drawable/ic_location" android:tint="@color/colorAccent" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:layout_marginStart="10dp" android:orientation="vertical"> <TextView android:id="@+id/address1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="ABC Street Sector 1/2" android:textAppearance="@style/TextAppearance.AppCompat.Subhead" /> <TextView android:id="@+id/country1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="XYZ Country" android:textAppearance="@style/TextAppearance.AppCompat.Small" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:layout_marginStart="10dp" android:orientation="vertical"> <TextView android:id="@+id/addres2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="ABC Street Sector 1/2" android:textAppearance="@style/TextAppearance.AppCompat.Subhead" /> <TextView android:id="@+id/country2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="XYZ Country" android:textAppearance="@style/TextAppearance.AppCompat.Small" /> </LinearLayout> </LinearLayout> </LinearLayout> <View android:id="@+id/extraSpace" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> </androidx.core.widget.NestedScrollView> </LinearLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout> </layout>
قدم سوم : ساخت آداپتر برای bottom sheet
در این مرحله کلاسی extend شده از BottomSheetDialogFragment می سازیم. که سوپرکلاس مربوطه دارای متدهایی ست که باید override شوند. مثل متد ()onCreateDialog. کلاسی که می نویسیم در واقع آداپتری ست که باید برای bottomSheet بسازیم.
import android.app.Dialog; import android.content.res.Resources; import android.content.res.TypedArray; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.databinding.DataBindingUtil; import com.codixlab.fullscreenbottomsheet.databinding.LayoutBottomSheetBinding; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialog; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; public class BottomSheet extends BottomSheetDialogFragment { BottomSheetBehavior bottomSheetBehavior; LayoutBottomSheetBinding bi; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { BottomSheetDialog bottomSheet = (BottomSheetDialog) super.onCreateDialog(savedInstanceState); //inflating layout View view = View.inflate(getContext(), R.layout.layout_bottom_sheet, null); //binding views to data binding. bi = DataBindingUtil.bind(view); //setting layout with bottom sheet bottomSheet.setContentView(view); bottomSheetBehavior = BottomSheetBehavior.from((View) (view.getParent())); //setting Peek at the 16:9 ratio keyline of its parent. bottomSheetBehavior.setPeekHeight(BottomSheetBehavior.PEEK_HEIGHT_AUTO); //setting max height of bottom sheet bi.extraSpace.setMinimumHeight((Resources.getSystem().getDisplayMetrics().heightPixels) / 2); bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View view, int i) { if (BottomSheetBehavior.STATE_EXPANDED == i) { showView(bi.appBarLayout, getActionBarSize()); hideAppBar(bi.profileLayout); } if (BottomSheetBehavior.STATE_COLLAPSED == i) { hideAppBar(bi.appBarLayout); showView(bi.profileLayout, getActionBarSize()); } if (BottomSheetBehavior.STATE_HIDDEN == i) { dismiss(); } } @Override public void onSlide(@NonNull View view, float v) { } }); //aap bar cancel button clicked bi.cancelBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { dismiss(); } }); //aap bar edit button clicked bi.editBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(getContext(), "Edit button clicked", Toast.LENGTH_SHORT).show(); } }); //aap bar more button clicked bi.moreBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(getContext(), "More button clicked", Toast.LENGTH_SHORT).show(); } }); //hiding app bar at the start hideAppBar(bi.appBarLayout); return bottomSheet; } @Override public void onStart() { super.onStart(); bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); } private void hideAppBar(View view) { ViewGroup.LayoutParams params = view.getLayoutParams(); params.height = 0; view.setLayoutParams(params); } private void showView(View view, int size) { ViewGroup.LayoutParams params = view.getLayoutParams(); params.height = size; view.setLayoutParams(params); } private int getActionBarSize() { final TypedArray array = getContext().getTheme().obtainStyledAttributes(new int[]{android.R.attr.actionBarSize}); int size = (int) array.getDimension(0, 0); return size; } }
به کمک متد onCreateDialog می توان دیالوگ اختصاصی و دلخواهی برای برنامه ساخت.
چند ثابت برای bottomSheet ها تعریف شده که شامل :
- PEEK_HEIGHT_AUTO که باعث می شود دیالوگ با نسبت 16:9 نمایش داده شود.
- STATE_COLLAPSED و STATE_EXPANDED که به ترتیب در مورد باز و بسته شدن دیالوگ مربوطه عمل می کنند.
BottomSheetBehavior
دارای کلاس تو در توی BottomSheetCallback است. که به کمک آن نتیجه دلخواه در برنامه نمایش داده می شود. مثلا اینکه هنگام نمایش bottomSheet قسمت appBar محو شود، یا هنوز نمایش داده شود. در این کلاس متدهایی داریم از جمله :
- ()onSlide که این متد هنگام کشیده شدن bottom sheet صدا زده می شود.
- ()onStateChanged وقتی bottom sheet تغییر وضعیت می دهد.
قدم چهارم : تکمیل نمودن کلاس MainActivity
حالا bottomsheet آماده استفاده است. به سراغ کلاس MainActivity می رویم و آن را بکار می گیریم.
import android.os.Bundle; import android.view.View; import androidx.appcompat.app.AppCompatActivity; import androidx.databinding.DataBindingUtil; import com.codixlab.fullscreenbottomsheet.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { ActivityMainBinding bi; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); bi = DataBindingUtil.setContentView(this, R.layout.activity_main); init(); } private void init() { bi.openBottomSheet.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { BottomSheet bottomSheet = new BottomSheet(); bottomSheet.show(getSupportFragmentManager(),bottomSheet.getTag()); } }); } }
قدم آخر : افزودن bottomSheet به ویوی MainActivity
به راحتی layout مربوط به MainActivity را مانند زیر کامل می کنیم :
<?xml version="1.0" encoding="utf-8"?> <layout 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"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/openBottomSheet" android:layout_width="294dp" android:layout_height="45dp" android:backgroundTint="@color/colorAccent" android:text="Open" android:textColor="@android:color/white" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout>