I use three dialogs in my app, one DatePickerDialog in a dialogfragment, one dialogfragment with a custom layout through an alertdialog and one alertdialog without a dialogfragment. My dateopickerdialog looks like this. Notice the titlepart which is completely orange.
My second dialogfragmen does not have the titlepart covering the whole upper part of the window which I would like to have.
Here is the relevant part of my style.xml
<style name="ScheduleCompareTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/primaryColor</item>
<item name="colorPrimaryDark">#color/primaryDarkColor</item>
<item name="colorAccent">#color/primaryLightColor</item>
<item name="android:dialogTheme">#style/ScheduleCompareDialogTheme</item>
<item name="android:alertDialogTheme">#style/ScheduleCompareDialogTheme</item>
</style>
<style name="ScheduleCompareDialogTheme">
<item name="android:windowTitleStyle">#style/ScheduleCompareDialogTitle</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowCloseOnTouchOutside">false</item>
<item name="android:buttonBarButtonStyle">#style/Widget.MaterialComponents.Button.TextButton</item>
</style>
<style name="ScheduleCompareDialogTitle">
<item name="android:background">#color/primaryLightColor</item>
<item name="android:textAppearance">#style/DialogWindowTitleText</item>
</style>
<style name="DialogWindowTitleText">
<item name="android:textColor">#color/primaryTextColor</item>
<item name="android:textSize">24sp</item>
</style>
The first part is my base theme, the second is the style used for dialogs and alertdialogs, the third part for the dialogtitle and the fourth for the title text. The styling works but somehow not the whole title area background is colored orange. Judging from the second picture I assumed there was some standard padding applied so I set the padding in the style name="ScheduleCompareDialogTheme" to 0dp. This produced the following effect.
So it works but only for the toppadding. Setting the paddingLeft and paddingRight explicitly to 0 dp did not produce any results.
Searching the internet I found something using android:topDark but this also produced no effect.
Does someone know how to extend the orange rectangle to cover the whole of the top area?
Aditionally I would like to mention that the datepickerdialog was already styled like it is shown just using the basetheme.
EDIT:
This is the layoutfile for the customdialog. I removed some code which is not shown in the picture, but is used when someone with more rights uses the app.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
xmlns:app="http://schemas.android.com/apk/res-auto">
.......
<RadioButton
android:id="#+id/radio_teachers"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Docenten" />
.......
<RadioButton
android:id="#+id/radio_students"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Leerlingen" />
........
<AutoCompleteTextView
android:id="#+id/acl_textinput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=""
android:hint="Zoeknaam"
app:layout_constraintTop_toBottomOf="#id/check_own_properties"
app:layout_constraintLeft_toLeftOf="#id/check_own_properties"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="50dp"
android:dropDownHeight="150dp"
android:inputType="textNoSuggestions"/>
</android.support.constraint.ConstraintLayout>
And the relevant part of the dialogfragment
public class OverlaySchedulePickerDialogFragment extends DialogFragment
implements CompoundButton.OnCheckedChangeListener,
View.OnClickListener {
private final String DEBUGTAG = "ScheduleDialog";
private Context mContext;
private ScheduleViewModel mScheduleViewModel;
private AlertDialog mDialog;
//variables for the layout
RadioGroup radiogroupBranches, radiogroupMainLeft, radiogroupMainRight;
RadioButton radioTeachers,radioStudents,radioLocations,radioGroups;
List<RadioButton> radioBranches;
CheckBox checkOwnProperties;
AutoCompleteTextView aclInputvalue;
StringsAdapter aclAdapter;
.....
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
mScheduleViewModel = ViewModelProviders.of(getActivity()).get(ScheduleViewModel.class);
mScheduleViewModel.loadDataFromDB(Constants.GETBRANCHESFROMDB, null);
LayoutInflater inflater = getActivity().getLayoutInflater();
View fragmentLayout = inflater.inflate(R.layout.dialogfragment_secondschedulepicker, null);
//get references to the layoutelements
radiogroupMainLeft = fragmentLayout.findViewById(R.id.radiogroup_main_left);
radiogroupMainRight = fragmentLayout.findViewById(R.id.radiogroup_main_right);
radiogroupBranches = fragmentLayout.findViewById(R.id.radiogroup_branches);
radioTeachers = fragmentLayout.findViewById(R.id.radio_teachers);
radioStudents = fragmentLayout.findViewById(R.id.radio_students);
aclInputvalue = fragmentLayout.findViewById(R.id.acl_textinput);
//set listeners for the checkbox and radiobuttons
checkOwnProperties.setOnCheckedChangeListener(this);
radioStudents.setOnClickListener(this);
radioTeachers.setOnClickListener(this);
radioGroups.setOnClickListener(this);
radioLocations.setOnClickListener(this);
radioTeachers.performClick();
//set properties of the AutoCompleteText
aclAdapter = new StringsAdapter(mContext, R.layout.autocomplete_listitem,new ArrayList<>());
aclInputvalue.setAdapter(aclAdapter);
aclInputvalue.setThreshold(2);
aclInputvalue.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
if(textView.getId() == aclInputvalue.getId() && actionId == IME_NULL && keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
if (mDialog.getButton(DialogInterface.BUTTON_POSITIVE).isEnabled()) {
mDialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
return true;
} else {
if (aclAdapter.suggestions.size() > 0) {
String text = aclAdapter.suggestions.get(0);
aclInputvalue.setText(text);
aclInputvalue.setSelection(aclInputvalue.getText().length());
return true;
}
}
}
return false;
}
});
//add textWatcher to validate the entered text
aclInputvalue.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
String stringToValidate = editable.toString();
if(mStringList!=null) {
mDialog.getButton(DialogInterface.BUTTON_POSITIVE)
.setEnabled(mStringList.contains(stringToValidate));
}
}
});
//build the dialog
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
dialogBuilder.setView(fragmentLayout);
dialogBuilder.setTitle(R.string.overlayschedulepickerdialog_title);
dialogBuilder.setPositiveButton(R.string.dialog_positive_button_text, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
//Input is valid so transfer to mScheduleViewModel and ask for secondSchedule
int position = mStringList.indexOf(aclInputvalue.getText().toString());
mScheduleViewModel.setOverlaySchedule(mScheduleType,position);
}
});
dialogBuilder.setNegativeButton(R.string.dialog_negative_button_text, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
mDialog = dialogBuilder.create();
mDialog.setOnShowListener(new DialogInterface.OnShowListener() {
#Override
public void onShow(DialogInterface dialog) {
((AlertDialog)dialog).getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
}
});
return mDialog;
}
END EDIT
Related
Little add: I need a way of doing it when the TextInputLayout/EditText is not focused, not between focused-not focused states
I'm looking for a way to change the textColorHint property of TextInputLayout only when the text is present in the TextInputEditText (directly from XML).
If I use that property android:textColorHint="#color/black", it changes the hint color also if the TextInputEditText is empty.
Is there a way to set two different colors for the hint in the two states?
I add a couple of images to explain better
What I want:
when text is empty
when text is filled
What I don't want:
hint has "with text" color
post scriptum: yeah, I could've used two more different colors for this example, but it should be understandable anyway :P
Suppose you take two color, lets say color1 when text is empty and color2 when text is filled, try below approach.
When Text Filled
<style name="TextAppearance.App.TextInputLayout_filled" parent="#android:style/TextAppearance">
<item name="android:textColor">#color/color2</item>
<item name="android:textSize">#dimen/text_size_12</item>
</style>
When Text Empty
<style name="TextAppearance.App.TextInputLayout_empty" parent="#android:style/TextAppearance">
<item name="android:textColor">#color/color1</item>
<item name="android:textSize">#dimen/text_size_12</item>
</style>
Theme
<style name="TextLabel" parent="TextAppearance.AppCompat">
<!-- Hint color and label color in FALSE state -->
<item name="android:textColorHint">#color/color1</item>
<item name="android:textSize">#dimen/text_size_16</item>
</style>
XML for TextInputLayout
<android.support.design.widget.TextInputLayout
android:id="#+id/til_first_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/TextLabel"
app:hintTextAppearance="#style/TextAppearance.App.TextInputLayout_filled">
<android.support.design.widget.TextInputEditText
android:id="#+id/edt_first_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/first_name_caps"
android:imeOptions="actionNext"
android:maxLines="1"
android:nextFocusForward="#+id/til_last_name"
android:singleLine="true"
android:textColor="#android:color/black"/>
</android.support.design.widget.TextInputLayout>
and code
edt_first_name.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
if (edt_first_name.getText().toString().length() > 0){
til_first_name.setHintTextAppearance(R.style.TextAppearance_App_TextInputLayout_filled);
}else {
til_first_name.setHintTextAppearance(R.style.TextAppearance_App_TextInputLayout_empty);
}
}
});
Use style
<style name="TextInputLayout" parent="#android:style/TextAppearance">
<!-- Hint color and label color in FALSE state -->
<item name="android:textColorHint">#color/color_hint</item>
<item name="android:textColor">#color/color_black</item>
<item name="android:fontFamily">#font/helveticaneue</item>
<!-- Label color in TRUE state and bar color FALSE and TRUE State -->
<item name="colorAccent">#color/color_hint</item>
<item name="colorControlNormal">#color/color_hint</item>
<item name="colorControlActivated">#color/color_hint</item>
<item name="colorControlHighlight">#color/color_hint</item>
</style>
use this style in xml
<android.support.design.widget.TextInputLayout
android:id="#+id/layoutFirstName"
style="#style/TextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_8sdp"
app:hintTextAppearance="#style/TextInputStyle.Hint">
<android.support.design.widget.TextInputEditText
android:id="#+id/editFirstName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/first_name"
android:imeOptions="actionDone"
android:inputType="text"
android:importantForAutofill="noExcludeDescendants"
android:theme="#style/InputTextEditTextNew" />
</android.support.design.widget.TextInputLayout>
For the TextInputEditText set the color of the hint when it is empty with this attribute:
android:textColorHint="#color/yourcolor"
when it is not empty you have to set the color of the floating hint with this style:
<style name="TextInputLayoutStyle" parent="TextAppearance.AppCompat">
<item name="colorControlNormal">#color/colornormalcolor</item>
<item name="colorControlActivated">#color/anothercolor</item>
</style>
and use it in the TextInputLayout xml:
android:theme="#style/TextInputLayoutStyle"
After some research looks like we can not achieve what we are looking for from xml layout only. To do that we definitely need to customize TextInputLayout. Then can simply use that in xml layout file wherever is required.
Here is the customized TextInputLayout
public class CustomTextInputLayout extends TextInputLayout {
public CustomTextInputLayout(Context context) {
this(context, null);
}
public CustomTextInputLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomTextInputLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
registerFocusChangeListener();
}
private void registerFocusChangeListener() {
getEditText().setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
String text = getEditText().getText().toString();
boolean isEmpty = TextUtils.isEmpty(text);
if (!isEmpty) { // EditText is not empty, doesn't matter whether it is focused or unfocused
setHintTextAppearance(R.style.TextAppearance_Dark);
} else { // EditText is empty
setHintTextAppearance(R.style.TextAppearance_Light);
}
}
});
}
}
I've gone over several stackoverflow posts, but have sadly not yet found something that works for me: I have a TimePreference that uses a timepicker. I believe due to my color scheme the numbers are not showing up (seems to be white on white): Screenshot of how it looks at the moment
I have tried to figure out how to influence the number colors through a style. No luck, but for some stackoverflow answers pointing to android:TimePickerStyleand similar which requires a higher API than what I have set (API 15).
I've also tried to use a custom-layout, but I am not quite sure where best to call the layout in the TimePreference.class (or I happened on the right place, but had no luck either).
I've also researched the possibility of the changing the clock-face color, but didn't get any further there either.
The TimePreference currently looks like this (no custom-layout implemented):
public class TimePreference extends DialogPreference {
private int lastHour = 0;
private int lastMinute = 0;
private boolean isAm;
private TimePicker picker = null;
private static int getHour(String time) {
String[] pieces = time.split(":");
return (Integer.parseInt(pieces[0]));
}
private static int getMinute(String time) {
String[] pieces = time.split(":");
return (Integer.parseInt(pieces[1]));
}
public TimePreference(Context ctxt, AttributeSet attrs) {
super(ctxt, attrs);
setPositiveButtonText("Set");
setNegativeButtonText("Cancel");
}
#Override
protected View onCreateDialogView() {
picker = new TimePicker(getContext());
//check locale settings whether to use am/pm or 24 hour display
picker.setIs24HourView(false);
return (picker);
}
#Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
}
#Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
lastHour = picker.getCurrentHour();
lastMinute = picker.getCurrentMinute();
String time = String.valueOf(lastHour) + ":" + String.valueOf(lastMinute);
if (callChangeListener(time)) {
persistString(time);
}
}
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return (a.getString(index));
}
#Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
String time;
if (restoreValue) {
if (defaultValue == null) {
time = getPersistedString("12:00 pm");
} else {
time = getPersistedString(defaultValue.toString());
}
} else {
time = defaultValue.toString();
}
lastHour = getHour(time);
lastMinute = getMinute(time);
new TimePickerDialog.OnTimeSetListener() {
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
isAm = hourOfDay < 12;
}
};
}
public String getTime() {
String meridianId;
if (isAm) {
if (lastHour > 12) {
meridianId = " pm";
} else {
meridianId = " am";
}
} else {
meridianId = "";
}
return lastHour + ":" + lastMinute + meridianId;
}
}
And my style.xml looks like this at the moment:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
(…)
<item name="android:dialogTheme">#style/DialogTheme</item>
<item name="android:alertDialogTheme">#style/DialogTheme</item>
</style>
<style name="AppAlertDialogContent" parent="Theme.AppCompat.Dialog">
<!-- To tint EditText and TimePicker -->
<item name="colorAccent">#color/colorAccent</item>
<!-- Used for the title and text -->
<item name="android:textColorPrimary">#color/colorPrimaryDark</item>
<item name="android:windowBackground">#color/colorPrimary</item>
</style>
<style name="DialogTheme" parent="Theme.AppCompat.Dialog">
<!-- Used for the title and text -->
<item name="android:textColorPrimary">#color/colorLightAccent</item>
<!-- Used for the background -->
<item name="android:background">#color/colorPrimary</item>
<!-- Used for the buttons -->
<item name="colorAccent">#color/colorLightAccent</item>
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
</style>
I'd appreciate your help in ensuring that the numbers can actually be read. Whether by custom-layout, styles or some other nifty approach. Thank you, for your help.
After digging deep into the Timepicker widget I had to concede that this is not possible under API 21. So I ended up building my own custom UI, using two Numberpickers and a ToggleButton. This gave me enough reachable views where I could control the colors sufficiently to ensure it is readable. For thisandroid:theme is the lifesaver, as this is where I can then (finally!) influence the colors.
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/timePickerLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="horizontal">
<!-- hour -->
<NumberPicker
android:id="#+id/dialog_hour_np"
android:layout_width="#dimen/picker_width"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/half_space"
android:focusable="true"
android:focusableInTouchMode="true"
android:solidColor="#color/colorPrimaryDark"
android:theme="#style/AppTheme.Picker"
app:layout_constraintEnd_toStartOf="#+id/dialog_minute_np"
app:layout_constraintStart_toStartOf="parent" />
<!-- minute -->
<NumberPicker
android:id="#+id/dialog_minute_np"
android:layout_width="#dimen/picker_width"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/half_space"
android:focusable="true"
android:focusableInTouchMode="true"
android:solidColor="#color/colorPrimaryDark"
android:theme="#style/AppTheme.Picker"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/dialog_amPm_tb"
app:layout_constraintStart_toEndOf="#+id/dialog_hour_np"
app:layout_constraintTop_toTopOf="parent" />
<!-- AM / PM -->
<ToggleButton
android:id="#+id/dialog_amPm_tb"
style="?android:attr/textAppearanceLargeInverse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="#dimen/half_space"
android:layout_marginStart="#dimen/std_space"
android:background="#color/colorPrimaryDark"
android:textColor="#color/colorLightAccent"
android:textOff="#string/time_string_pm"
android:textOn="#string/time_string_am"
app:layout_constraintBottom_toBottomOf="#+id/dialog_minute_np"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/dialog_minute_np"
app:layout_constraintTop_toTopOf="#+id/dialog_minute_np" />
and the theme:
<style name="AppTheme.Picker" parent="Theme.AppCompat.Light.NoActionBar" >
<item name="android:textColorPrimary">#color/colorAccent</item>
<item name="android:textColorSecondary">#color/colorLightAccent</item>
</style>
I'm trying to make a custom dialog displaying the DatePicker, but the element adds an extra margin/padding to the right of the view. This happens only on Android 7.1.1, Nexus 6P, but works perfectly fine on other lower resolution phones. How do I remove the extra padding?
My XML layout code:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<DatePicker
android:id="#+id/date_picker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:endYear="2012"
android:startYear="1930" />
</LinearLayout>
It looks like this on Android 7.1.1:
Edit: Added my Java code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_attributes);
assert getSupportActionBar() != null;
getSupportActionBar().setTitle("Register");
final TextView birthDateSelectedTextView = (TextView) findViewById(R.id.text_view_birth_date);
Button dialogOpenButton = (Button) findViewById(R.id.button_dialog_date_picker);
dialogOpenButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final Dialog dialog = new Dialog(UserAttributesActivity.this);
final AlertDialog.Builder builder = new AlertDialog.Builder(UserAttributesActivity.this);
LayoutInflater inflater = getLayoutInflater();
View dialogView = inflater.inflate(R.layout.dialog_date_picker, null);
builder.setView(dialogView);
final DatePicker datePicker = (DatePicker) dialogView.findViewById(R.id.date_picker);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
day = datePicker.getDayOfMonth();
month = datePicker.getMonth() + 1;
year = datePicker.getYear();
String date = "" + day + "/" + month + "/" + year;
birthDateSelectedTextView.setText(date);
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.show();
}
});
}
Add Style with AlertDialog.Builder like as follow.
AlertDialog.Builder builder = new AlertDialog.Builder(UserAttributesActivity.this, android.R.style.Theme_DeviceDefault_Light_Dialog_NoActionBar);
#Ankita is right, but if you are using AppCompat things are a bit more involved:
Define a new style and extend AppCompat's Light.Dialog style
<style name="DatePickerDialogStyle" parent="#style/Theme.AppCompat.Light.Dialog">
...
</style>
Then add attributes to mimic the NoActionBar part:
<style name="DatePickerDialogStyle" parent="#style/Theme.AppCompat.Light.Dialog">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
Lastly, now that you are no longer getting app compat colors from your AppTheme, copy them over to your new theme:
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="colorPrimary">#color/primary</item>
<item name="colorPrimaryDark">#color/primary_dark</item>
<item name="colorAccent">#color/accent</item>
</style>
<style name="DatePickerDialogStyle" parent="#style/Theme.AppCompat.Light.Dialog">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="colorPrimary">#color/primary<item>
<item name="colorPrimaryDark">#color/primary_darkitem>
<item name="colorAccent">#color/accent</item>
</style>
Then apply this new theme:
AlertDialog.Builder builder
= new AlertDialog.Builder(UserAttributesActivity.this,
DatePickerDialogStyle);
Use this
DatePickerDialog.Builder builder = null;
// 5.0+ 需要更换主题以去除右侧白边
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder = new DatePickerDialog.Builder(this.getActivity(),
android.R.style.Theme_DeviceDefault_Light_Dialog_NoActionBar);
}
// 4.4 不需要,相反加上会有白边
else {
builder = new DatePickerDialog.Builder(this.getActivity());
}
If you are using a class like androidx.fragment.app.DialogFragment(). Do this:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Set the dialog style.
setStyle(STYLE_NO_TITLE, android.R.style.Theme_DeviceDefault_Light_Dialog_NoActionBar)
}
What I want to do:
When using an EditText embedded in a TextInputLayout I want to ...
Set the Color of the label to GREEN when it's de-focused and floating above the EditText because the user has already entered some value
Set the Color of the label to RED when it's de-focused and located inside the EditText, because the user has not yet entered a value
I do not want to change the hint text color of all my EditTexts to RED, but only when they're wrapped in a TextInputLayout (I don't need a general approach - a specific approach like setting a theme/style for each TextInputLayout in the layout XML would be fine)
Preserve (i.e. don't change) the accent color (YELLOW) used to color the floating label when the user has focused the field.
What I have tried:
Setting the below as a theme/style on the TextInputLayout does satisfy 1. but not 2.
<style name="FloatingLabel" parent="Widget.Design.TextInputLayout">
<item name="android:textColorHint">#color/red</item>
</style>
Setting a specific color on my embedded EditText that changes the hint text to another color:
android:textColorHint="#color/text_placeholder_gray"
actually causes an overlap of hint texts when the label is moved from it's floating position back into the Edittext as a hint (i.e. no text).
Setting this:
<style name="TextAppearence.App.TextInputLayout" parent="#android:style/TextAppearance">
<item name="android:textColor">#color/main_color</item>
on the TextInputLayout:
<android.support.design.widget.TextInputLayout
...
app:hintTextAppearance="#style/TextAppearence.App.TextInputLayout" >
Changes the hint label color but it also does so for the focused state - which means 4 is not satisfied.
And since a picture says more than a tousand words (all fields are in non-focused state):
How to achieve a setup that satisfies criteria 1-4 ?
I had a similar problem: I needed to implement a text input layout in which the label has different colours for empty (when there is no text entered in the edit text), "filled" and focused state. My main problem was how to differentiate between the empty and the filled state as setting a different colour for the focused state was already easy using selectors. In the end I decided to define a custom "empty text" state and implement my custom text input layout (which extends the normal text input layout).
Here is some code:
In res/values/attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
...
<!-- Custom state for the text input layout to determine whether the label is shown above some text or not -->
<declare-styleable name="EmptyTextState">
<attr name="state_empty_text" format="boolean"/>
</declare-styleable>
</resources>
The custom text input layout:
public class EmptyStateTextInputLayout extends TextInputLayout {
private boolean emptyText = true;
private static final int[] EMPTY_TEXT_STATE = new int[]{R.attr.state_empty_text};
public EmptyStateTextInputLayout(Context context) {
super(context);
}
public EmptyStateTextInputLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EmptyStateTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected int[] onCreateDrawableState(int extraSpace) {
int[] state = super.onCreateDrawableState(extraSpace + 1);
if (emptyText) {
mergeDrawableStates(state, EMPTY_TEXT_STATE);
}
return state;
}
public void setEmptyTextState(boolean emptyTextState) {
this.emptyText = emptyTextState;
refreshDrawableState();
}
#Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (child instanceof EditText) {
EditText editText = (EditText) child;
if (!TextUtils.isEmpty(editText.getText())) {
setEmptyTextState(false);
}
editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
if (!TextUtils.isEmpty(editable)) {
setEmptyTextState(false);
} else {
setEmptyTextState(true);
}
}
});
}
super.addView(child, index, params);
}
}
XML selector to set the colour of label in different states (res/color/input_field_floating_label.xml):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:color="#color/focused_text_color" android:state_focused="true" />
<item android:color="#color/placeholder_color" app:state_empty_text="true"/>
<item android:color="#color/primary_text_color"/> <!-- default color -->
</selector>
Style for the input text layout (in res/values/styles.xml):
<style name="EditTextLayout">
...
<item name="android:textColorHint">#color/input_field_floating_label</item>
</style>
Theme and style for the edit text (still in res/values/styles.xml):
<style name="EditTextTheme">
...
<item name="android:textColorHint">#color/input_field_floating_label</item>
</style>
<style name="EditText">
<item name="android:theme">#style/EditTextTheme</item>
...
</style>
Usage:
<com.package.path.widget.EmptyStateTextInputLayout
style="#style/DarkEditTextLayout"
android:layout_height="wrap_content"
android:layout_width="match_parent"
...
>
<EditText
style="#style/EditText"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.package.path.widget.EmptyStateTextInputLayout>
I recommend this blog post to get an idea of working with custom states: http://code.neenbedankt.com/example-of-custom-states-in-android-components/
(This is a random image of showing a Dialog found on the Internet.)
I've been implementing a custom Dialog. I could handle almost everything on the dialog except for that default black dim background under the dialog itself, but over the entire screen behind it. Basically I want to change its color and alpha value.
I've been wandering through StackOverflow but only answers I found were about changing background of Dialog itself. In any case if you need it, here's my simple codes.
CustomDialog.java
public class HTDialog extends Dialog{
public HTDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setCanceledOnTouchOutside(true);
setContentView(R.layout.custom_dialog);
}
}
custom_dialog.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/dialog_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="280dp"
android:background="#drawable/bg_popup"
android:paddingTop="20dp">
<ImageView
android:id="#+id/dialog_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:src="#drawable/icon" />
</RelativeLayout>
This is a workaround but it's not really a pure solution because background touch is disabled and should be configured manually.
First, set custom dialog theme like this.
styles.xml
<style name="CustomDialogTheme" parent="android:Theme.Dialog">
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">false</item>
<item name="android:windowBackground">#android:color/transparent</item>
</style>
Setting windowIsFloating to false forces Dialog view to be expanded to full screen. Setting windowBackground to transparent removes default black dim background under Dialog. windowNoTitle option gets rid of the upper title bar.
CustomDialog.java
Apply the theme and construct your custom_dialog view as follows.
public HTCustomDialog(Context context) {
super(context, R.style.CustomDialogTheme);
setContentView(R.layout.custom_dialog);
}
custom_dialog.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/main_solid_80">
<RelativeLayout
android:id="#+id/dialog_root"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:background="#drawable/bg_popup"
android:padding="16dp">
</RelativeLayout>
Now that CustomDialog view is a full-screen view, set background of your root layout to whatever color you'd like.
Sample result
I mosaiced the result a bit.
use custom style.
<style name="transparent_dialog_borderless" parent="android:Theme.Dialog">
<item name="android:windowFrame">#null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:background">#FF333333</item>
<item name="android:windowBackground">#null</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
android:backgroundDimEnabled:control the black dim background
This worked for me:
val dialog = AlertDialog.Builder(context)
.setView(view)
.setCancelable(true)
.setPositiveButton(R.string.done_label, { dialog, _ -> dialog.dismiss() })
.create()
dialog.window.setDimAmount(0f)
dialog.show()
dialog.window.setDimAmount(0f) is the key.
Try to set the style for your dialog windows,
Example:
Dialog dialog = new Dialog(context,android.R.style.Theme_Translucent_NoTitleBar);
set a float value for backgroundDimAmount between 0-1 (it is a float value)
<style name="DarkTransparentBgDialog" parent="#android:style/Theme.Dialog">
<item name="android:backgroundDimEnabled">true</item>
<item name="android:backgroundDimAmount">0.87</item>
</style>
in DialogFragment (in Kotlin)
override fun getTheme() = R.style.DarkTransparentBgDialog
The following custom DatePickerDoalog class not only makes dim color customizable but also it makes dim appearing animated
/**
* #author Taras Yurkiv #Devlight
*/
public class DatePickerDialogCustomDim extends DatePickerDialog {
private final long animDuration = 100;
private float dimAmount = 0.7f;
private Drawable dimDrawable;
private ViewGroup root;
private OnDismissListener outsideDismissListener;
private final OnDismissListener dismissListener = new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
final ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(dimDrawable,
PropertyValuesHolder.ofInt("alpha", (int) (255 * dimAmount), 0));
animator.setTarget(dimDrawable);
animator.setDuration(animDuration);
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
ViewGroupOverlay overlay = root.getOverlay();
overlay.remove(dimDrawable);
}
});
animator.start();
if (outsideDismissListener != null)
outsideDismissListener.onDismiss(dialog);
}
};
#TargetApi(Build.VERSION_CODES.N)
public DatePickerDialogCustomDim(#NonNull Context context) {
this(context, 0);
}
#TargetApi(Build.VERSION_CODES.N)
public DatePickerDialogCustomDim(#NonNull Context context, #StyleRes int themeResId) {
this(context, themeResId, null, -1, -1, -1);
init(context);
}
public DatePickerDialogCustomDim(#NonNull Context context,
#Nullable OnDateSetListener listener,
int year,
int month,
int dayOfMonth) {
this(context, 0, listener, year, month, dayOfMonth);
}
public DatePickerDialogCustomDim(#NonNull Context context,
#StyleRes int themeResId,
#Nullable OnDateSetListener listener,
int year,
int monthOfYear,
int dayOfMonth) {
super(context, themeResId, listener, year, monthOfYear, dayOfMonth);
init(context);
}
private void init(Context context) {
root = ((Activity) context).getWindow().getDecorView().findViewById(android.R.id.content);
super.setOnDismissListener(dismissListener);
}
public void setDimAmount(#FloatRange(from = 0, to = 1f) float dim) {
dimAmount = dim;
}
#Override
public void show() {
super.show();
dimDrawable = new ColorDrawable(Color.WHITE); // a dim color
dimDrawable.setBounds(0, 0, root.getWidth(), root.getHeight());
ViewGroupOverlay overlay = root.getOverlay();
overlay.add(dimDrawable);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(dimDrawable,
PropertyValuesHolder.ofInt("alpha", 0, (int) (255 * dimAmount)));
animator.setTarget(dimDrawable);
animator.setDuration(animDuration);
animator.start();
}
#Override
public void setOnDismissListener(#Nullable OnDismissListener listener) {
outsideDismissListener = listener;
}
}
it works in conjunction of a style
<style name="DatePickerDialogTheme" parent="Theme.AppCompat.Light.Dialog">
<item name="colorAccent">#color/accent</item>
<item name="android:textColorLink">#color/primary</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
try the code,
View checkBoxView = View.inflate(context, R.layout.alertbox, null);
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setView(checkBoxView);
builder.setCancelable(false);
Dialog d = builder.create();
d.getWindow().setBackgroundDrawable(new ColorDrawable(0));
d.setView(checkBoxView, 0, 0, 0, 0);
d.show();
nb: the line d.setView(checkBoxView, 0, 0, 0, 0); will make it...