1. 程式人生 > >Android安卓自定義由底部彈出對話方塊

Android安卓自定義由底部彈出對話方塊

努力不一定立刻會有好的結果,但一定是朝著好的方向                           ——李尚龍 《你所謂的穩定,不過是在浪費生命》


開發中遇到一個日期選擇器的需求,就是介面中有兩段文字顯示日期,點選之後從底部彈出日期選擇器。查閱了很多資料後發現官方有一個DatePicker日期選擇器,但是它只有一個日期,而且排版動畫也不符合我們得要求,所以廢了好的的功夫,把兩個DatePicker自定義佈局,嵌到Dialog控制元件裡,實現由底彈出的動畫效果。

廢話不多說,一步一步放出程式碼(提前說明程式碼為Kotlin,讀者根據所需自行調整):

專案原始碼打包在此:點選下載


目錄

1、首先放出activity_main.xml程式碼:

2、新建我們自定義的佈局檔案date_picker.xml程式碼:

 3、新增由底向上彈出的樣式檔案styles.xml程式碼:

4、新建自定義DateDialog類檔案,DateDialog.kt 程式碼:

5、最後MainActivity.kt程式碼:


1、首先放出activity_main.xml程式碼:

//////////////////////////////activity_main.xml/////////////////////////////////////////
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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="com.feds.datepickerdialog.MainActivity">
    <LinearLayout
        android:id="@+id/date_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" >
        <TextView
            android:id="@+id/start_date_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="****-**-**"
            android:textSize="25sp"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=" ------- "
            android:textSize="25sp"/>
        <TextView
            android:id="@+id/end_date_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="****-**-**"
            android:textSize="25sp" />
    </LinearLayout>
</android.support.constraint.ConstraintLayout>

2、新建我們自定義的佈局檔案date_picker.xml程式碼:

//////////////////////////////////date_picker.xml////////////////////////////////////////
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#ffffffff"
    android:layout_gravity="bottom"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="From"
        android:layout_gravity="center" />
    <DatePicker
        android:id="@+id/date_picker1"
        android:theme="@android:style/Theme.Holo.Light.NoActionBar"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:calendarViewShown="false"
        android:datePickerMode="spinner" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="To"
        android:layout_gravity="center"/>
    <DatePicker
        android:id="@+id/date_picker2"
        android:theme="@android:style/Theme.Holo.Light.NoActionBar"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:calendarViewShown="false"
        android:datePickerMode="spinner" />
</LinearLayout>

 3、新增由底向上彈出的樣式檔案styles.xml程式碼:

/////////////////////////////////////styles.xml////////////////////////////////////////////
<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
    <style name="ActionSheetDialogStyle" parent="@android:style/Theme.Dialog">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowFrame">@null</item>
        <item name="android:backgroundDimEnabled">true</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowAnimationStyle">@style/ActionSheetDialogAnimation</item>
    </style>
    <style name="ActionSheetDialogAnimation" parent="@android:style/Animation.Dialog">
        <item name="android:windowEnterAnimation">@anim/actionsheet_dialog_in</item>
        <item name="android:windowExitAnimation">@anim/actionsheet_dialog_out</item>
    </style>
</resources>

4、新建自定義DateDialog類檔案,DateDialog.kt 程式碼:

//////////////////////////////////DateDialog.kt//////////////////////////////////////////
class DateDialog(context: Context?, theme:Int) : Dialog(context,theme) {

    private var dateString1: String=""
    private var dateString2: String=""

    @SuppressLint("NewApi", "InflateParams")
    @RequiresApi(Build.VERSION_CODES.N)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val dialogWindow = this.window
        val lp: WindowManager.LayoutParams = dialogWindow.attributes
        val inflate = LayoutInflater.from(context).inflate(R.layout.date_picker, null)
        this.setContentView(inflate)
        dialogWindow.setGravity(Gravity.BOTTOM)
        lp.width = android.view.ViewGroup.LayoutParams.MATCH_PARENT
        dialogWindow.attributes = lp

        date_picker1.descendantFocusability = DatePicker.FOCUS_BLOCK_DESCENDANTS
        date_picker2.descendantFocusability = DatePicker.FOCUS_BLOCK_DESCENDANTS

        val calendar: Calendar = Calendar.getInstance()
        val year = calendar.get(Calendar.YEAR)
        val mindate = (year-1).toString() +"-"+ "12" +"-"+ "31"
        date_picker1.minDate = getStringToDate(mindate,"yyyy-MM-dd")
        date_picker1.maxDate = System.currentTimeMillis()
        date_picker2.minDate = getStringToDate(mindate,"yyyy-MM-dd")
        date_picker2.maxDate = System.currentTimeMillis()

        date_picker1.setOnDateChangedListener { _, _:Int, _:Int, _:Int ->
            dateString1 = date_picker1.year.toString() +"-"+ (date_picker1.month+1).toString() +"-"+
                    date_picker1.dayOfMonth.toString()
            val dateLong1 = getStringToDate(dateString1,"yyyy-MM-dd")
            dateString2 = date_picker2.year.toString() +"-"+ (date_picker2.month+1).toString() +"-"+
                    date_picker2.dayOfMonth.toString()
            val dateLong2 = getStringToDate(dateString2,"yyyy-MM-dd")
            if (dateLong1 > dateLong2){
                date_picker1.updateDate(date_picker2.year,date_picker2.month,date_picker2.dayOfMonth)
            }
        }
        date_picker2.setOnDateChangedListener { _, _: Int, _: Int, _: Int ->
            dateString1 = date_picker1.year.toString() +"-"+ (date_picker1.month+1).toString() +"-"+
                    date_picker1.dayOfMonth.toString()
            val dateLong1 = getStringToDate(dateString1,"yyyy-MM-dd")
            dateString2 = date_picker2.year.toString() +"-"+ (date_picker2.month+1).toString() +"-"+
                    date_picker2.dayOfMonth.toString()
            val dateLong2 = getStringToDate(dateString2,"yyyy-MM-dd")
            if (dateLong2 < dateLong1){
                date_picker1.updateDate(date_picker2.year,date_picker2.month,date_picker2.dayOfMonth)
            }
        }
    }

    fun startDate(): String {
        return dateString1
    }
    fun endDate(): String {
        return dateString2
    }

    @RequiresApi(Build.VERSION_CODES.N)
    private fun getStringToDate(dateString: String, pattern: String): Long {

        val dateFormat = SimpleDateFormat(pattern)
        var date = Date()
        try {
            date = dateFormat.parse(dateString)
        } catch (e: ParseException) {
            e.printStackTrace()
        }
        return date.time
    }

}

5、最後MainActivity.kt程式碼:

////////////////////////////////////MainActivity.kt//////////////////////////////////////
class MainActivity : AppCompatActivity(), View.OnClickListener {


    private lateinit var datedialog: DateDialog
    private lateinit var startDate: String
    private lateinit var endDate: String

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val calendar: Calendar = Calendar.getInstance()
        val year = calendar.get(Calendar.YEAR).toString()
        val month = (calendar.get(Calendar.MONTH) + 1).toString()
        val day = calendar.get(Calendar.DAY_OF_MONTH).toString()
        startDate = "$year-$month-$day"
        endDate = "$year-$month-$day"
    }

    override fun onResume() {
        super.onResume()
        datedialog = DateDialog(this,R.style.ActionSheetDialogStyle)
        date_view.setOnClickListener(this)

        start_date_text.text = startDate
        end_date_text.text = endDate

        datedialog.setOnDismissListener {
            if (datedialog.startDate() != "") {
                start_date_text.text = datedialog.startDate()
            }
            if (datedialog.endDate() != "") {
                end_date_text.text = datedialog.endDate()
            }
        }
    }

    override fun onClick(v: View?) {
        when(v?.id){
            R.id.date_view ->{
                datedialog.show()
            }
        }
    }
}