I have implemented a System Alert Window, And that window has its own UI. But when dark mode is enabled, then that layout is overriding the colours I have given.
private fun showAlert(context: Context,message:String){
val builder: AlertDialog.Builder = AlertDialog.Builder( ContextThemeWrapper(context, R.style.RigTheme))
val inflater: LayoutInflater = LayoutInflater.from(context)
val dialogView: View = inflater.inflate(R.layout.layout_rig_alert, null)
dialogView.findViewById<TextView>(R.id.tvMessage).text = message
builder.setView(dialogView)
val alert: AlertDialog = builder.create()
val window = alert.window ?: return
window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
window.requestFeature(Window.FEATURE_NO_TITLE)
val layoutFlag: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
WindowManager.LayoutParams.TYPE_PHONE
}
window.setType(layoutFlag)
alert.setCanceledOnTouchOutside(false)
alert.show()
val lp: WindowManager.LayoutParams = WindowManager.LayoutParams()
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
window.setGravity(Gravity.CENTER)
lp.copyFrom(window.attributes)
//This makes the dialog take up the full width
//This makes the dialog take up the full width
lp.width = WindowManager.LayoutParams.WRAP_CONTENT
lp.height = WindowManager.LayoutParams.WRAP_CONTENT
window.attributes = lp
// Click stuff
}
And the style
<style name="RigTheme" parent="Theme.AppCompat.Light.Dialog.Alert">
<item name="colorAccent">#color/light_red</item>
<item name="android:background">#color/white</item>
<item name="android:textColorPrimary">#color/txt_grey</item>
<item name="android:windowBackground">#android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
</style>
layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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="wrap_content"
android:layout_height="wrap_content"
app:cardElevation="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/curve_bg"
android:padding="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="#+id/iv_close"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="#drawable/close"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/warning"
android:textColor="#color/light_red"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/iv_close" />
<TextView
android:id="#+id/tvMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:padding="20dp"
android:textColor="#color/txt_grey"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvTitle" />
<Button
android:id="#+id/btnCancel"
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:background="#drawable/button_rect_un_selected"
android:text="#string/cancel"
android:textAllCaps="false"
android:textColor="#color/txt_grey"
app:layout_constraintEnd_toStartOf="#+id/btnDoit"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/tvMessage" />
<Button
android:id="#+id/btnDoit"
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:background="#drawable/button_rect_selected"
android:text="#string/do_it_now"
android:textAllCaps="false"
android:textColor="#color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#+id/btnCancel"
app:layout_constraintTop_toBottomOf="#id/tvMessage" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
I have 2 issues with this code.
Issue 1
The dark mode is overriding the colour combination
original UI
when dark mode is enabled
Issue 2
I need to align the widgets in the centre. I have given WRAP_CONTENT, but the dialog is taking most of the screen width. and of course, the widgets are aligned left.
check this tip from the docs:
Tip: If you want a custom dialog, you can instead display an Activity as a dialog instead of using the Dialog APIs. Simply create an activity and set its theme to Theme.Holo.Dialog in the manifest element:
<activity android:theme="#android:style/Theme.Holo.Dialog" >
That's it. The activity now displays in a dialog window instead of fullscreen.
I haven't tried it, but i think that inside the activity it will be easier to place your views without the alignment issues, also you can specify a Light theme with Theme.Holo.Light.Dialog.
Related
I need to fit 4 circular progress bars horizontally, like this:
so I decided to use new material component Circular Progress Indicator (https://material.io/components/progress-indicators/android). I spread chain these 4 progress bar
in constrait layout, but them don't scale. It looks like they are still having deafult 24dp size. Even if I try to hardcode width and height to 200dp for example, the output is still small progress bar.
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="#+id/progressBarCalories"
style="#style/ProgressBarCircular"
android:layout_marginTop="32dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="6dp"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintTop_toBottomOf="#id/wrapperCookingTime"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="#id/progressBarProtein"
tools:progress="75"/>
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="#+id/progressBarProtein"
style="#style/ProgressBarCircular"
android:layout_marginTop="32dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintTop_toBottomOf="#id/wrapperCookingTime"
app:layout_constraintStart_toEndOf="#id/progressBarCalories"
app:layout_constraintEnd_toStartOf="#id/progressBarCarbs"
tools:progress="75"/>
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="#+id/progressBarCarbs"
style="#style/ProgressBarCircular"
android:layout_marginTop="32dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintTop_toBottomOf="#id/wrapperCookingTime"
app:layout_constraintStart_toEndOf="#id/progressBarProtein"
app:layout_constraintEnd_toStartOf="#id/progressBarFat"
tools:progress="75"/>
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="#+id/progressBarFat"
style="#style/ProgressBarCircular"
android:layout_marginTop="32dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="16dp"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintTop_toBottomOf="#id/wrapperCookingTime"
app:layout_constraintStart_toEndOf="#id/progressBarCarbs"
app:layout_constraintEnd_toEndOf="parent"
tools:progress="75"/>
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="#+id/progressBar"
style="#style/ProgressBarCircular"
android:layout_marginTop="32dp"
app:layout_constraintWidth_min="200dp"
android:minWidth="200dp"
android:layout_width="200dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/progressBarFat"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:progress="75"/>
You have to use the indicatorSize attribute:
<com.google.android.material.progressindicator.CircularProgressIndicator
android:indeterminate="true"
android:layout_width="100dp"
android:layout_height="100dp"
app:indicatorSize="90dp"
app:indicatorColor="#color/colorPrimary"
../>
In version:
implementation 'com.google.android.material:material:1.5.0-alpha01'
You can set size using the following attribute:
app:indicatorSize="180dp"
app:trackThickness="10dp"
Full xml item will look something like:
<com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:indicatorSize="180dp"
app:trackThickness="10dp"
app:trackColor="#color/colorPrimary"
app:indicatorColor="#color/colorPrimaryDark"
android:layout_gravity="center_horizontal"
android:progress="80"
app:trackCornerRadius="8dp"
android:layout_marginTop="30dp"/>
Please Note: You need to set XML Display Theme to "MeterialTheme" inorder to see UI updates.
For those using data-binding, you can use
#BindingAdapter("bindProgressSizeToViewWidth")
fun bindProgressSizeToViewWidth(circularProgressIndicator: CircularProgressIndicator, view: View?) {
view ?: LogEventUtils.logApiError("bindProgressSizeToViewWidth: null view").run { return } // safty line you can remove it
view.post {
circularProgressIndicator.indicatorSize = view.measuredWidth
}
}
XML (just give the text padding 12dp & center it within the circularProgressIndicator)
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/progressTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:lineSpacingExtra="4sp"
android:padding="12dp"
tools:text="4/15"
android:textColor="#color/pumpkin_orange"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="#id/circularProgressIndicator"
app:layout_constraintBottom_toBottomOf="#+id/circularProgressIndicator"
app:layout_constraintEnd_toEndOf="#+id/circularProgressIndicator"
app:layout_constraintTop_toTopOf="#+id/circularProgressIndicator" />
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="#+id/circularProgressIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:indeterminate="false"
android:progress="#{40}"
app:bindProgressSizeToViewWidth="#{progressTv}"
app:indicatorColor="?colorPrimary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:trackColor="#color/battleship_grey" />
Results
I think that's because the maxHeight and maxWidth of the progressBar is set to 48dp in the style. You have to override it to make the bar scale.
I am currently using a scroll view inside an Alert Dialog and need the scroll view to grow in height until the dialog reaches its maximum default height. It's a bit tough for me to explain so i have attached an illustration to help. Hope it does.
The issue i'm getting is the scrollview does not grow in height and even if i remove the app:layout_constraintBottom_toTopOf="#id/linearLayout4", it grows however the bottom part will be partially hidden by the button layout. This is my current code :
<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:id="#+id/filter_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/dialog_box"
android:minHeight="300dp"
android:elevation="12dp">
<TextView
android:id="#+id/filter_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="#string/filter"
style="#style/element_header"
android:textColor="#color/textColorDark"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/filter_reset_btn"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:text="#string/reset"
style="#style/text_info_nBold"
android:textSize="14sp"
android:textColor="#color/textColorDark"
app:layout_constraintBottom_toBottomOf="#+id/filter_header"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/filter_header" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="#id/linearLayout4"
app:layout_constraintTop_toBottomOf="#id/filter_header"
app:layout_constraintVertical_bias="0.0">
<androidx.core.widget.NestedScrollView
android:id="#+id/filter_scroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true"
android:layout_marginTop="16dp"
android:scrollbarFadeDuration="1000">
<!-- VIEWS INSIDE HERE -->
</androidx.core.widget.NestedScrollView>
</LinearLayout>
<LinearLayout
android:id="#+id/linearLayout4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/dialog_bottombar_layout"
android:orientation="horizontal"
android:padding="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<Button
android:id="#+id/dialog_secondary_button"
style="#style/low_emphasis_btn"
android:layout_width="0dp"
android:layout_marginEnd="8dp"
android:layout_weight="1"
android:backgroundTint="#color/textColorDark"
android:text="#string/dialog_cancel"
android:textColor="#color/textColorDark"
android:visibility="visible" />
<Button
android:id="#+id/dialog_primary_button"
style="#style/high_emphasis_btn"
android:layout_width="0dp"
android:layout_weight="1"
android:text="#string/apply" />
</LinearLayout>
Any help would be appreciated :)
Alert dialogs tend to wrap their content or can be forced to be full screen. A size in between the optimizes the screen real estate takes a some work, but it is not impossible.
One approach is to let the system lay out the alert dialog but, before it is displayed, use a ViewTreeObserver.OnGlobalLayoutListener to examine the resulting size of the dialog. In the layout listener, the size of the dialog can be adjusted up to fit the contents of the scrolling view or adjusted up to full screen if the scrolling view contents are too large for the screen.
Here is a demo app that shows how this can be done. Comments in the code explain more.
MainActivity.kt
class MainActivity : AppCompatActivity(), View.OnClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onClick(v: View) {
val text = when (v.id) {
R.id.customDialogShort -> getString(R.string.short_string)
R.id.customDialogMedium -> getString(R.string.lorem_medium)
else -> getString(R.string.lorem_long)
}
// Specifying the viewGroup as a parent to the inflater makes no difference.
val dialogView = LayoutInflater.from(v.context).inflate(R.layout.con_custom_view, null, false) as ConstraintLayout
(dialogView.findViewById(R.id.textView) as TextView).text = text
val alertDialog = AlertDialog.Builder(this).setView(dialogView).create()
val decorView = alertDialog.window!!.decorView
decorView.setBackgroundResource(R.drawable.alert_dialog_background)
// We need a layout pass to determine how big everything is and needs to be. Place a hook
// at the end of the layout process to examine the layout before display.
decorView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
decorView.viewTreeObserver.removeOnGlobalLayoutListener(this)
// Find out how much of the scrolling view is usable by its child.
val scrollingView: NestedScrollView = decorView.findViewById(R.id.filter_scroll)
val scrollingViewPadding = scrollingView.paddingTop + scrollingView.paddingBottom
val scrollingUsableHeight = scrollingView.height - scrollingViewPadding
// If the child view fits in the scrolling view, then we are done.
val childView = scrollingView.getChildAt(0)
if (childView.height <= scrollingUsableHeight) {
return
}
// Child doesn't currently fit in the scrolling view. Resize the top-level
// view so the child either fits or is forced to scroll because the maximum
// height is reached. First, find out how much space is allowed by the decor view.
val displayRectangle = Rect()
decorView.getWindowVisibleDisplayFrame(displayRectangle)
val decorViewPadding = decorView.paddingTop + decorView.paddingBottom
val decorUsableHeight = displayRectangle.height() - decorViewPadding - scrollingViewPadding
// Compute the height of the dialog that will 100% fit the scrolling content and
// reduce it if it won't fit in the maximum allowed space.
val heightToFit = dialogView.height + childView.height - scrollingUsableHeight
dialogView.minHeight = min(decorUsableHeight, heightToFit)
}
})
var buttonOk: Button = dialogView.findViewById(R.id.dialog_primary_button)
buttonOk.setOnClickListener { alertDialog.dismiss() }
buttonOk = dialogView.findViewById(R.id.dialog_secondary_button)
buttonOk.setOnClickListener { alertDialog.dismiss() }
alertDialog.show()
}
}
activity_main.xml
<LinearLayout
android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="#+id/customDialogShort"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="Short text" />
<Button
android:id="#+id/customDialogMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="Medium text" />
<Button
android:id="#+id/customDialogLong"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="Long text" />
</LinearLayout>
con_custom_view
Custom Layout for the AlertDialog.
<TextView
android:id="#+id/filter_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="#string/filter"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/filter_reset_btn"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:text="#string/reset"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="#+id/filter_header"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/filter_header" />
<androidx.core.widget.NestedScrollView
android:id="#+id/filter_scroll"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="16dp"
android:padding="16dp"
android:scrollbarFadeDuration="1000"
app:layout_constraintBottom_toTopOf="#id/linearLayout4"
app:layout_constraintTop_toBottomOf="#id/filter_header">
<TextView
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="#string/lorem_long" />
</androidx.core.widget.NestedScrollView>
<LinearLayout
android:id="#+id/linearLayout4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<Button
android:id="#+id/dialog_secondary_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_weight="1"
android:text="#string/dialog_cancel"
android:visibility="visible" />
<Button
android:id="#+id/dialog_primary_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/apply" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
I have a problem with this specific dialog, I implemented it as an option to be shown in the Options Menu in my toolbar but it doesn't show the dialog's contents when I clicked on the option. I have tried these with other dialog layouts I have implemented and all of them work when I implemented them here so I have a hunch that the problem is with the XML layout but I can't seem to find the problem.
Code:
else if(id == R.id.action_setting)
{
Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.dialog_settings);
dialog.setTitle("Settings");
CheckBox set_splash = dialog.findViewById(R.id.setting_check);
boolean have_splash =pref.getBoolean(SplashActivity.HAVE_SPLASH,false);
if(have_splash)
set_splash.setChecked(true);
else
set_splash.setChecked(false);
ImageButton confirm_btn = dialog.findViewById(R.id.setting_confirm);
ImageButton cancel_btn = dialog.findViewById(R.id.setting_cancel);
confirm_btn.setOnClickListener(v -> {
boolean new_splash = set_splash.isChecked();
edit.putBoolean(SplashActivity.HAVE_SPLASH,new_splash);
edit.commit();
dialog.dismiss();
});
cancel_btn.setOnClickListener(v -> dialog.dismiss());
dialog.show();
}
XML :
<?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="wrap_content">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/linearLayout5">
<ImageButton
android:id="#+id/setting_confirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#drawable/button_highlight_dark"
android:paddingVertical="20dp"
app:srcCompat="#drawable/ic_confirm" />
<ImageButton
android:id="#+id/setting_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#drawable/button_highlight_dark"
android:paddingVertical="20dp"
app:srcCompat="#drawable/ic_cancel" />
</LinearLayout>
<TextView
android:id="#+id/setting_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#color/themeDark"
android:paddingVertical="10dp"
android:paddingLeft="10dp"
android:text="#string/settings"
android:textColor="#color/white"
android:textSize="10pt"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="#+id/linearLayout5"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#color/themeLight"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/setting_text">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="6"
android:textColor="#color/white"
android:paddingVertical="20dp"
android:paddingLeft="10dp"
android:text="#string/splash_setting"
android:textSize="10pt" />
<CheckBox
android:id="#+id/setting_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
The match_parent parameters in your dialog are ignored. Therefore, the dialog has a width of 0.
The easiest way to get the correct height and width, is by using an AlertDialog.Builder.
If a customized AlertDialog isn't enough, you can make the dialog full size by following this answer:
Android get full width for custom Dialog
Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.dialog_settings);
Window window = dialog.getWindow();
window.setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
I am using TextInputLayout to take advantage of the floating hint and error display, the validation logic triggers when I press the continue button, it works fine if I don't select any textInput, the error is displayed correctly, but if I select a textInput, dismiss the keyboard and then press the continue button, the textInput is highlited in red as expected but the error text is not displayed.
What seems to be weird is that I tried the same code, same layout on a Acitvity and it worked fine (I am using a Fragment for this), but I would much rather stick to Fragment.
I also inspected the layout (when the error was not displayed) and the error textView seems to be there (in the view tree you can see the textView inside the TextInputLayout with a width of 0 and the text set to whatever I set it to)
My layout is:
<androidx.core.widget.NestedScrollView 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:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white">
<TextView
android:id="#+id/text_acc_details"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="24dp"
android:text="#string/sign_up_details"
android:textAppearance="#style/headerText"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="#+id/linear_acc_details"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/text_acc_details">
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/text_input_name"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:boxBackgroundMode="outline"
app:errorEnabled="true"
app:hintAnimationEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/text_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/sign_up_text_name"
android:inputType="text"
android:textColor="#color/textColour"
android:textSize="18sp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/text_input_last_name"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:errorEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/text_last_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/sign_up_text_last_name"
android:inputType="text"
android:textColor="#color/textColour"
android:textSize="18sp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/text_input_email1"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:errorEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/text_email1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/sign_up_text_email1"
android:inputType="text"
android:textColor="#color/textColour"
android:textSize="18sp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/text_input_email2"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/text_email2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/sign_up_text_email2"
android:inputType="text"
android:textColor="#color/textColour"
android:textSize="18sp" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="#+id/button_sign_up_continue"
style="#style/PrimaryButton"
android:layout_width="300dp"
android:layout_marginBottom="23dp"
android:enabled="true"
android:text="#string/sign_up_button_continue"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
My Fragment code:
class SignUpFragment: Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
val rootView = inflater.inflate(R.layout.fragment_sign_up, container, false)
return rootView
}
override fun onStart() {
super.onStart()
button_sign_up_continue.setOnClickListener {
validateText()
}
}
private fun validateText() {
if (text_name.text.isNullOrEmpty()) {
text_input_name.error = resources.getText(R.string.sign_up_error_text)
} else {
text_input_name.error = null
}
if (text_last_name.text.isNullOrEmpty()) {
text_input_last_name.error = resources.getText(R.string.sign_up_error_text)
} else {
text_input_last_name.error = null
}
val isValidEmail = Patterns.EMAIL_ADDRESS.toRegex().matches(text_email1.text.toString())
if (text_email1.text.isNullOrEmpty() || !isValidEmail) {
text_input_email1.error = resources.getText(R.string.sign_up_invalid_email)
} else {
text_input_email1.error = null
}
}
The gif shows how by tapping the button first works fine, but if I select a textInput first and then tap the button the error text is not displayed (it is set and is there by checking in the layout inspector tool but the width is 0 for some reason)
After spending quite a lot of time in this issue, I found out that this seems to be a Material Android issue (at least on com.google.android.material:material:1.1.0 library version), you can find the issue tracker here:
https://issuetracker.google.com/issues/136435162
For the time being I found a work around to fix the errorTextView's width issue by creating a TextInputLayout extension and updating the errorTextView width manually:
val errorTextView = this.findViewById<TextView>(R.id.textinput_error)
var params = errorTextView?.layoutParams
params?.width = yourWidth
errorTextView?.layoutParams = params
It is not pretty but it does the trick for now, hope it helps someone
Put this method inside onActivityCreated() instead of onStart()
button_sign_up_continue.setOnClickListener {
validateText()
}
In my code, I'm presenting a custom alert dialog by inflating a layout and set it as the dialog's view.
The problem I'm having is that the text looks OK in the Android Studio's design tool, but at run-time, the dialog becomes smaller and the text takes more lines.
I tried different approaches to fix it, but didn't acquire the wanted result.
For the layout, I'm using constraint layout and the text is "wrap content".
Here's my code:
//inflate alert layout
LayoutInflater inflater = LayoutInflater.from(this);
final View view = inflater.inflate(R.layout.connectivity_issue_counter, null);
//set builder
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setView(view);
dialog.setCancelable(false);
final AlertDialog alert = dialog.create();
//define dialog buttons and counter......//
alert.show();
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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/alertBackground">
<TextView
android:id="#+id/connectivity_issue_title"
style="#style/customAlertTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="50dp"
android:text="#string/connectivity_issue_title"
app:layout_constraintEnd_toStartOf="#+id/connectivity_issue_wait"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/connectivity_issue_wait"
style="#style/customAlertTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="#string/connectivity_issue_wait"
app:layout_constraintEnd_toStartOf="#+id/connectivity_issue_counter_text"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/connectivity_issue_counter_text"
style="#style/customAlertTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/connectivity_issue_main_text"
style="#style/customAlertMainText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="#string/connectivity_issue_main_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/connectivity_issue_title" />
<Button
android:id="#+id/connectivity_isuue_button"
style="#style/customAlertButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="#string/stop"
app:layout_constraintEnd_toStartOf="#+id/guideline21"
app:layout_constraintStart_toStartOf="#+id/guideline22"
app:layout_constraintTop_toBottomOf="#+id/connectivity_issue_main_text" />
<android.support.constraint.Guideline
android:id="#+id/guideline20"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.82" />
<android.support.constraint.Guideline
android:id="#+id/guideline21"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.75" />
<android.support.constraint.Guideline
android:id="#+id/guideline22"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.25" />
</android.support.constraint.ConstraintLayout>
*Another interesting thing - on a different tablet (both the same model) the dialog looks bigger and wider.
I'll appreciate any help.
As Davidaz suggested, I've changed the text size from sp to dp and it helped to solve the problem.
¿Maybe the text is bigger on that phone? I can't see the customAlertTitle style, but I suppose the text is on "SP", and these are "DP" but text-size dependent (if the phone is set to show the text on a big font from it's settings tab, it will increase it's size).
Maybe a solution could be to set the sizes to "DP", but you won't let the people change it, so it has counter effects.
Another idea that comes to my mind is that the size of the screen you are previewing on the preview is larger than your phone's screen.
The last thing I would try is to change the 'android.R.id.message' TextView's size by hand after creating the dialog. Once you show it you can access the message's textview by calling for it's id,
TextView messageTv = (TextView) alert.findViewById(android.R.id.message);
messageTv.setTextSize(X);
Edit: Don't mind that last idea, as you are inflating your own layout, maybe you can try to access your id and change it the same way, but with R.id.connectivity_issue_wait