浏览代码

Add dialogWrapContent parameter to customView that is used by the datetime dialogs. Resolves #1770.

Aidan Follestad 6 年之前
父节点
当前提交
257bb29ec2

+ 18 - 5
core/src/main/java/com/afollestad/materialdialogs/MaterialDialog.kt

@@ -24,6 +24,7 @@ import android.graphics.drawable.Drawable
 import androidx.annotation.CheckResult
 import androidx.annotation.DimenRes
 import androidx.annotation.DrawableRes
+import androidx.annotation.Px
 import androidx.annotation.StringRes
 import com.afollestad.materialdialogs.Theme.Companion.inferTheme
 import com.afollestad.materialdialogs.WhichButton.NEGATIVE
@@ -49,7 +50,7 @@ internal fun assertOneSet(
   b: Any?,
   a: Int?
 ) {
-  if ((a == null || a == 0) && b == null) {
+  if (a == null && b == null) {
     throw IllegalArgumentException("$method: You must specify a resource ID or literal value")
   }
 }
@@ -85,7 +86,7 @@ class MaterialDialog(
     internal set
   var buttonFont: Typeface? = null
     internal set
-  @DimenRes private var maxWidthRes: Int = R.dimen.md_dialog_max_width
+  @Px private var maxWidth: Int? = null
 
   internal val view: DialogLayout = inflate(R.layout.md_dialog_base)
 
@@ -307,8 +308,20 @@ class MaterialDialog(
    *
    * This value only takes effect when calling [show].
    */
-  @CheckResult fun maxWidthRes(@DimenRes res: Int): MaterialDialog {
-    this.maxWidthRes = res
+  fun maxWidth(
+    @DimenRes res: Int? = null,
+    @Px literal: Int? = null
+  ): MaterialDialog {
+    assertOneSet("maxWidth", res, literal)
+    val shouldSetConstraints = this.maxWidth != null && this.maxWidth == 0
+    this.maxWidth = if (res != null) {
+      windowContext.resources.getDimensionPixelSize(res)
+    } else {
+      literal!!
+    }
+    if (shouldSetConstraints) {
+      setWindowConstraints(this.maxWidth)
+    }
     return this
   }
 
@@ -320,7 +333,7 @@ class MaterialDialog(
 
   /** Opens the dialog. */
   override fun show() {
-    setWindowConstraints(maxWidthRes)
+    setWindowConstraints(maxWidth)
     preShow()
     super.show()
     postShow()

+ 17 - 1
core/src/main/java/com/afollestad/materialdialogs/customview/DialogCustomViewExt.kt

@@ -20,6 +20,7 @@ import androidx.annotation.CheckResult
 import androidx.annotation.LayoutRes
 import com.afollestad.materialdialogs.MaterialDialog
 import com.afollestad.materialdialogs.assertOneSet
+import com.afollestad.materialdialogs.utils.MDUtil.waitForLayout
 
 internal const val CUSTOM_VIEW_NO_VERTICAL_PADDING = "md.custom_view_no_vertical_padding"
 
@@ -47,14 +48,29 @@ fun MaterialDialog.customView(
   @LayoutRes viewRes: Int? = null,
   view: View? = null,
   scrollable: Boolean = false,
-  noVerticalPadding: Boolean = false
+  noVerticalPadding: Boolean = false,
+  dialogWrapContent: Boolean = false
 ): MaterialDialog {
   assertOneSet("customView", view, viewRes)
   config[CUSTOM_VIEW_NO_VERTICAL_PADDING] = noVerticalPadding
+
+  if (dialogWrapContent) {
+    // Postpone window measurement so custom view measures itself naturally.
+    maxWidth(literal = 0)
+  }
+
   this.view.contentLayout.addCustomView(
       res = viewRes,
       view = view,
       scrollable = scrollable
   )
+      .also {
+        if (dialogWrapContent) {
+          it.waitForLayout {
+            maxWidth(literal = measuredWidth)
+          }
+        }
+      }
+
   return this
 }

+ 3 - 1
core/src/main/java/com/afollestad/materialdialogs/internal/main/DialogContentLayout.kt

@@ -105,7 +105,7 @@ internal class DialogContentLayout(
     @LayoutRes res: Int?,
     view: View?,
     scrollable: Boolean
-  ) {
+  ): View {
     check(customView == null) { "Custom view already set." }
 
     if (view != null && view.parent != null) {
@@ -122,6 +122,8 @@ internal class DialogContentLayout(
       customView = view ?: inflate(res!!)
       addView(customView)
     }
+
+    return customView!!
   }
 
   fun haveMoreThanOneChild() = childCount > 1

+ 10 - 4
core/src/main/java/com/afollestad/materialdialogs/utils/DialogExt.kt

@@ -27,8 +27,8 @@ import android.view.inputmethod.InputMethodManager
 import android.widget.ImageView
 import android.widget.TextView
 import androidx.annotation.ColorInt
-import androidx.annotation.DimenRes
 import androidx.annotation.DrawableRes
+import androidx.annotation.Px
 import androidx.annotation.RestrictTo
 import androidx.annotation.RestrictTo.Scope
 import androidx.annotation.StringRes
@@ -46,12 +46,17 @@ import com.afollestad.materialdialogs.utils.MDUtil.resolveString
 import kotlin.math.min
 
 internal fun MaterialDialog.setWindowConstraints(
-  @DimenRes maxWidthRes: Int = R.dimen.md_dialog_max_width
+  @Px maxWidth: Int? = null
 ) {
   val win = window ?: return
   win.setSoftInputMode(SOFT_INPUT_ADJUST_RESIZE)
   val wm = win.windowManager ?: return
 
+  if (maxWidth == 0) {
+    // Postpone
+    return
+  }
+
   val display = wm.defaultDisplay
   val size = Point()
   display.getSize(size)
@@ -66,14 +71,15 @@ internal fun MaterialDialog.setWindowConstraints(
     val windowHorizontalPadding = getDimensionPixelSize(
         R.dimen.md_dialog_horizontal_margin
     )
-    val maxWidth = getDimensionPixelSize(maxWidthRes)
     val calculatedWidth = windowWidth - windowHorizontalPadding * 2
+    val actualMaxWidth =
+      maxWidth ?: context.resources.getDimensionPixelSize(R.dimen.md_dialog_max_width)
 
     view.maxHeight = windowHeight - windowVerticalPadding * 2
     val lp = WindowManager.LayoutParams()
         .apply {
           copyFrom(win.attributes)
-          width = min(maxWidth, calculatedWidth)
+          width = min(actualMaxWidth, calculatedWidth)
         }
     win.attributes = lp
   }

+ 23 - 0
core/src/main/java/com/afollestad/materialdialogs/utils/MDUtil.kt

@@ -25,6 +25,7 @@ import android.text.Editable
 import android.text.Html
 import android.text.TextWatcher
 import android.view.View
+import android.view.ViewTreeObserver
 import android.widget.EditText
 import android.widget.TextView
 import androidx.annotation.AttrRes
@@ -230,4 +231,26 @@ object MDUtil {
         )
     )
   }
+
+  @RestrictTo(LIBRARY_GROUP) fun <T : View> T.waitForLayout(block: T.() -> Unit) {
+    if (measuredWidth > 0 && measuredHeight > 0) {
+      this.block()
+      return
+    }
+
+    viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
+      var lastWidth: Int? = null
+
+      override fun onGlobalLayout() {
+        if (lastWidth != null && lastWidth == measuredWidth) {
+          viewTreeObserver.removeOnGlobalLayoutListener(this)
+          return
+        }
+        if (measuredWidth > 0 && measuredHeight > 0) {
+          lastWidth = measuredWidth
+          this@waitForLayout.block()
+        }
+      }
+    })
+  }
 }

+ 5 - 1
datetime/src/main/java/com/afollestad/materialdialogs/datetime/DatePickerExt.kt

@@ -33,7 +33,11 @@ fun MaterialDialog.datePicker(
   currentDate: Calendar? = null,
   dateCallback: DateTimeCallback = null
 ): MaterialDialog {
-  customView(R.layout.md_datetime_picker_date, noVerticalPadding = true)
+  customView(
+      R.layout.md_datetime_picker_date,
+      noVerticalPadding = true,
+      dialogWrapContent = true
+  )
 
   if (minDate != null) {
     getDatePicker().minDate = minDate.timeInMillis

+ 5 - 1
datetime/src/main/java/com/afollestad/materialdialogs/datetime/DateTimePickerExt.kt

@@ -47,7 +47,11 @@ fun MaterialDialog.dateTimePicker(
   show24HoursView: Boolean = false,
   dateTimeCallback: DateTimeCallback = null
 ): MaterialDialog {
-  customView(R.layout.md_datetime_picker_pager, noVerticalPadding = true)
+  customView(
+      R.layout.md_datetime_picker_pager,
+      noVerticalPadding = true,
+      dialogWrapContent = true
+  )
 
   val viewPager = getPager()
   viewPager.adapter = DateTimePickerAdapter()

+ 5 - 1
datetime/src/main/java/com/afollestad/materialdialogs/datetime/TimePickerExt.kt

@@ -34,7 +34,11 @@ fun MaterialDialog.timePicker(
   show24HoursView: Boolean = true,
   timeCallback: DateTimeCallback = null
 ): MaterialDialog {
-  customView(R.layout.md_datetime_picker_time, noVerticalPadding = true)
+  customView(
+      R.layout.md_datetime_picker_time,
+      noVerticalPadding = true,
+      dialogWrapContent = true
+  )
 
   getTimePicker().apply {
     setIs24HourView(show24HoursView)