I'm searching for a possibilitie to adjust the text color of the datepicker widget in an android honeycomb app. I knew that the widget inherent the global text-color which is white in my case, but i need a black text-color for the datepicker as the background here is light grey.
Anyone know how to fix this?
DONE IT
Did it in a Theme in the application styles.xml (basically set a style on all EditText fields)
I have this in /values-v11/ so it only affects >HC
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Theme.SelectDate" parent="#android:style/Theme.Holo.NoActionBar">
<item name="android:editTextStyle">#style/Widget.EditText.Black</item>
</style>
<style name="Widget.EditText.Black" parent="#android:style/Widget.EditText">
<item name="android:textColor">#color/black</item>
</style>
</resources>
Then in my AndroidManifest, for the Activity that uses the DatePicker:
<activity
android:name=".ui.phone.SelectDateActivity"
android:label="Date Selection"
android:screenOrientation="portrait"
android:theme="#style/Theme.SelectDate" />
That's it!
My Working Out:
I came to this conclusion by checking the DatePicker source:
https://github.com/android/platform_frameworks_base/blob/master/core/res/res/layout/date_picker.xml
That showed me the DatePicker used NumberPicker
https://github.com/android/platform_frameworks_base/blob/master/core/res/res/layout/number_picker.xml
https://github.com/android/platform_frameworks_base/blob/master/core/res/res/layout/number_picker_with_selector_wheel.xml
The NumberPicker uses an EditText
You can therefore style an EditText
android : how to change the style of edit text?
And if you search in this file for "editText" you will see you can set a style on all edittext fields in one Activity!
https://github.com/android/platform_frameworks_base/blob/master/core/res/res/values/themes.xml
You override this item:
<item name="editTextStyle">#android:style/Widget.EditText</item>
I have found this solution: debugging DatePicker object, I get the object jerarqy. Maybe it's not an elegant solution but it works:
private void setNumberPickerProperties(DatePicker dp)
{
LinearLayout l = (LinearLayout)dp.getChildAt(0);
if(l!=null)
{
l = (LinearLayout)l.getChildAt(0);
if(l!=null)
{
for(int i=0;i<3;i++)
{
NumberPicker np = (NumberPicker)l.getChildAt(i);
if(np!=null)
{
EditText et = (EditText)np.getChildAt(1);
et.setTextColor(Color.BLACK);
}
}
}
}
}
Hi there :) There is an EditText widget somewhere within the datepicker widget. You just have to find it. You can do this by using some creative coding and start searching through the childrens of the datepicker widget using methods like getChildAt(index) and getChildCount() and then loop through it.
You can also do something like this, but i'm not sure that it will work on all devices, better loop through the datepickers children:
DatePicker picker;
ViewGroup childpicker;
childpicker = (ViewGroup) findViewById(Resources.getSystem().getIdentifier("month" /*rest is: day, year*/, "id", "android"));
EditText textview = (EditText) picker.findViewById(Resources.getSystem().getIdentifier("timepicker_input", "id", "android"));
textview.setTextColor(Color.GREEN);
I hope this helps :)
Hmm I did it like this:
private void hackDatePickerTextColorToBlack(){
setTextColorBlack(datePicker);
}
private static void setTextColorBlack(ViewGroup v) {
int count = v.getChildCount();
for (int i = 0; i < count; i++) {
View c = v.getChildAt(i);
if(c instanceof ViewGroup){
setTextColorBlack((ViewGroup) c);
} else
if(c instanceof TextView){
((TextView) c).setTextColor(Color.BLACK);
}
}
}
This changes the text color to black but careful with recursion this could take some time.
Also when the date picker is used the text goes back to white so that sucks!
FYI here's the source for DatePicker: https://github.com/android/platform_frameworks_base/blob/master/core/res/res/layout/date_picker.xml
The EditTexts are NumberPickers
I had a similar issue, although I was looking to change the text size, but that's a minor detail. I used the same process to pick apart the View hierarchy and change the font size. However, once a month (or day or year) was changed, the font changed back to the original value. Great for viewing, bad for editing. I took the next step and added a change listener. Now when the value gets changed, it pops back to the preferred font size:
public void setFontSize(final int size) {
LinearLayout l = (LinearLayout) mPicker.getChildAt(0);
if (l != null) {
l = (LinearLayout) l.getChildAt(0);
if (l != null) {
for (int i = 0; i < 3; i++) {
NumberPicker np = (NumberPicker) l.getChildAt(i);
for (int x = 0; x < np.getChildCount(); x++) {
View view = np.getChildAt(x);
if ((view != null) && (view instanceof TextView)) {
final TextView tv = (TextView) view;
tv.setTextSize(size);
tv.setOnEditorActionListener(new OnEditorActionListener() {
public boolean onEditorAction(TextView v,
int actionId, KeyEvent event) {
tv.setTextSize(size);
return false;
}
});
}
}
}
}
}
}
Related
When using a TimePicker set to spinner mode, if I click on a number (minutes or hours), the number keyboard shows up.
But whenever I scroll any of the spinners, the keyboard changes to the text inputType.
How can I avoid this?
I've tried calling timePicker.setAddStatesFromChildren(true) and setting an OnTimeChangedListener, but that won't work, for if I scroll just enough for the spinner to move but not for the time to change, the listener is not triggered but the keyboard changes to text inputType anyway.
Also, timePicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS) is not what I'm looking for, for I still want the keyboard to show up, but only that it won't change its inputType to text.
In the end, I couldn't find which view was making the keyboard appear. I tried removing the next focus from every view inside the TimePicker, but nothing. Then, I thought the problem was that, since I was using a 24-hour format spinner, the view to blame was the hidden AM/PM CustomTextView inside the TimePicker. I made it non-focusable, but still the same issue. So I concluded that the problem was somewhere in the implementation of the TimePicker itself, who manages some event and displays the keyboard.
So I decided to iterate over the NumberPickers inside TimePicker —which are three— and set an OnScrollListener on them that hides the keyboard. But still, I get to see the text keyboard appearing before being dismissed. But that's the best I've managed to do.
public static <T extends View> List<T> getViewsByClassNameFromView(ViewGroup viewGroup, Class<T> clazz) {
final List<T> matches = new LinkedList<>();
final int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = viewGroup.getChildAt(i);
if (clazz.isInstance(child)) {
matches.add((T) child);
} else if (child instanceof ViewGroup) {
matches.addAll(getViewsByClassNameFromView((ViewGroup) child, clazz));
}
}
return matches;
}
public void hideSoftKeyboard(View view) {
InputMethodManager imm =
(InputMethodManager) view.getContext().getApplicationContext()
.getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
view.clearFocus();
}
private void fixTimePicker() {
final List<NumberPicker> numberPickers = ViewUtil.getViewsByClassNameFromView(timePicker, NumberPicker.class);
for (final NumberPicker numberPicker: numberPickers) {
numberPicker.setOnScrollListener(new NumberPicker.OnScrollListener() {
#Override
public void onScrollStateChange(NumberPicker view, int scrollState) {
hideSoftKeyboard(view);
}
});
}
}
android:descendantFocusability="blocksDescendants" use this attribute in DatePicker Xml and it will resolve your issue.
I'm new to Android and I'm implementing NumberPicker to one of my activities in my app. Below is the excerpt of my code:
picker = (NumberPicker)findViewById(R.id.order_confirm_bring_time_minute_picker);
picker.setMinValue(15);
picker.setMaxValue(120);
picker.setWrapSelectorWheel(false);
setNumberPickerTextColor(picker, android.R.color.black);
public boolean setNumberPickerTextColor(NumberPicker numberPicker, int color)
{
final int count = numberPicker.getChildCount();
for(int i = 0; i < count; i++){
View child = numberPicker.getChildAt(i);
if(child instanceof EditText){
try{
Field selectorWheelPaintField = numberPicker.getClass()
.getDeclaredField("mSelectorWheelPaint");
selectorWheelPaintField.setAccessible(true);
((Paint)selectorWheelPaintField.get(numberPicker)).setColor(color);
((EditText)child).setTextColor(color);
numberPicker.invalidate();
return true;
}
catch(NoSuchFieldException e){
Log.d("setNumberPickerTextColor", "NoSuchFieldException");
}
catch(IllegalAccessException e){
Log.d("setNumberPickerTextColor", "IllegalAccessException");
}
catch(IllegalArgumentException e){
Log.d("setNumberPickerTextColor", "IllegalArgumentException");
}
}
}
return false;
}
I've looked into this post for the setNumberPickerTextColor method. But it does not seem to work as I set my color to be changed to black, but it is not visible anymore. If I do not use the setNumberPickerTextColor method, then my default color is white, which can be seen when I highlight the text in the EditText field of the NumberPicker.
This is a screenshot of the NumberPicker when the color is not changed.
This is a screenshot of the NumberPicker when the color is changed to black or any other color (I have tested and they give the same result).
Would there be a way to customize the text color in my NumberPicker? Also, I know it is a different question, but the colors of the top and bottom 'bar' as well because they do not fit the color theme of my app. Thanks in advance for help.
You need to pass the resolved color to the setTextColor method, not the resource id.
((EditText)child).setTextColor(getResources().getColor(color));
I have extended EditTextPreference, but the Dialog Message won't display. This happens if I add the dialogMessage programatically or in the the preferences.xml.
Here is my onBindDialogView:
AutoCompleteTextView editText = mEditText;
editText.setText(getText());
ViewParent oldParent = editText.getParent();
if (oldParent != view) {
if (oldParent != null) {
((ViewGroup) oldParent).removeView(editText);
}
onAddEditTextToDialogView(view, editText);
}
Is the dialog message really absent? It's probably there but its text color might make it less (or not) visible. (Or try to dismiss software keyboard). Try experimenting with dialog messages having a number of "\n" characters and see if that affects dialog layout. If so, it means the dialog message is actually there but camouflaged too well.
EditTextPreference brings a text view (in the preference_dialog_edittext.xml) that replaces the existing one (in the alert_dialog.xml) for the dialog message, but unfortunately with different text style, which might cause a visibility problem under certain themes. Even their sizes are different.
One solution might be to obtain the text color and size from the original text view to be replaced and apply them to the new one, but I would suggest retaining the original text view instead, because it's more likely to be visually consistent if there are any future UI changes. Try adding the following overrides
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
super.onPrepareDialogBuilder(builder);
builder.setMessage(getDialogMessage()); // bring back the original text view
}
protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
int id = getContext().getResources().getIdentifier("edittext_container", "id", "android");
ViewGroup container = (ViewGroup) dialogView.findViewById(id);
container.removeAllViews(); // remove the new text view
super.onAddEditTextToDialogView(dialogView, editText);
}
If you think the dialog message and the edittext view is too far apart, they can be brought together a little closer by adding another override:
protected void showDialog(Bundle state) {
super.showDialog(state);
int id = getContext().getResources().getIdentifier("message", "id", "android");
TextView message = (TextView) getDialog().findViewById(id);
message.setPadding(message.getPaddingLeft(), message.getPaddingTop(), message.getPaddingRight(), 0);
}
and add the following line in the onAddEditTextToDialogView method after calling removeAllViews:
container.setPadding(container.getPaddingLeft(), 0, container.getPaddingRight(), container.getPaddingBottom());
I'm using ABS vers. 4 and I need to simply change the default "Done" text that is displayed besides the action mode close icon, but I really can't figure out how to do it.
I think that text needs to be customizable for at least two good reasons:
"Done" is not appropriate for all contexts (e.g. "Cancel" could be more appropriate, and I've seen some apps, such as the "My Files" app on Galaxy Tab, use it)
"Done" needs to be localized according to the user's language
Is it possible to do customize that text? If so can anyone tell me how to do it?
Thanks in advance.
EDIT
I've found a temporary workaround, that I post in the following:
private TextView getActionModeCloseTextView() {
// ABS 4.0 defines action mode close button text only for "large" layouts
if ((getResources().getConfiguration().screenLayout &
Configuration.SCREENLAYOUT_SIZE_MASK) ==
Configuration.SCREENLAYOUT_SIZE_LARGE)
{
// retrieves the LinearLayout containing the action mode close button text
LinearLayout action_mode_close_button =
(LinearLayout) getActivity().findViewById(R.id.abs__action_mode_close_button);
// if found, returns its last child
// (in ABS 4.0 there is no other way to refer to it,
// since it doesn't have an id nor a tag)
if (action_mode_close_button != null) return (TextView)
action_mode_close_button.getChildAt(action_mode_close_button.getChildCount() - 1);
}
return null;
}
That's the method I came up with. Please NOTE that it does heavily rely upon the structure of the abs__action_mode_close_item.xml of ABS 4.0.
This works for my scenario, but, as you can see, it cannot be considered sufficiently satisfying to promote it to a real "answer", that's why I only edited my previous post.
Hope that helps someone else, but I also hope that someone could share a better and cleaner solution.
You can use a theme to override the default icon:
<item name="actionModeCloseDrawable">#drawable/navigation_back</item>
<item name="android:actionModeCloseDrawable">#drawable/navigation_back</item>
I edited the code from PacificSky to be able to customize the color and font size of the close button, both in pre ICS and >ICS.
I created a method named customizeActionModeCloseButton
private void customizeActionModeCloseButton() {
int buttonId = Resources.getSystem().getIdentifier("action_mode_close_button", "id", "android");
View v = getGSActivity().findViewById(buttonId);
if (v == null) {
buttonId = R.id.abs__action_mode_close_button;
v = getGSActivity().findViewById(buttonId);
}
if (v == null)
return;
LinearLayout ll = (LinearLayout) v;
if (ll.getChildCount() > 1 && ll.getChildAt(1) != null) {
TextView tv = (TextView) ll.getChildAt(1);
tv.setText(R.string.close_action_mode);
tv.setTextColor(getResources().getColor(R.color.white));
tv.setTextSize(18);
}
}
and I call it just after calling startActionMode()
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
actionMode = getActivity().startActionMode(this);
customizeActionModeCloseButton();
return true;
}
It's been a while, but here's a slightly less hacky solution - putting it out there for posterity.
For Android versions < ICS
Put the following line in your application's strings.xml:
<string name="abs__action_mode_done">Cancel</string>
This overrides the TextView's (defined in ActionBarSherlock/res/layout-large/abs__action_mode_close_item.xml) android:text attribute.
For Android versions ICS and above
The native ActionBar functionality is used on ICS and up. You need to find and override the string associated with the done button, using the following code:
int buttonId = Resources.getSystem().getIdentifier("action_mode_close_button", "id", "android");
if (buttonId != 0)
{
View v = findViewById(buttonId);
if (v != null)
{
LinearLayout ll = (LinearLayout)v;
View child = ll.getChildAt(1);
if (child != null)
{
TextView tv = (TextView)child;
tv.setText(R.string.cancel);
}
}
}
Thanks for PacificSky's answer. It's useful for my case.
Something needs to be explained here is that findViewById(buttonId) might return null in some cases such as called in onCreateActionMode() function, because the LinearLayout for ActionMode close button not yet initialized at that time I guess.
I want to hide the action mode close button, so i just sendEmptyMessageDelayed in onCreateActionMode() and call PacificSky's 200ms later. It works for me.
Here is my approach with Java code:
private void customizeActionModeCloseButton(String title, int iconID) {
int buttonId = Resources.getSystem().getIdentifier("action_mode_close_button", "id", "android");
View v = findViewById(buttonId);
if (v == null) {
buttonId = R.id.abs__action_mode_close_button;
v = findViewById(buttonId);
}
if (v == null)
return;
LinearLayout ll = (LinearLayout) v;
if (ll.getChildCount() > 1 && ll.getChildAt(1) != null) {
//custom icon
ImageView img = (ImageView) ll.getChildAt(0);
img.setImageResource(iconID);
//custom text
TextView tv = (TextView) ll.getChildAt(1);
tv.setText(title);
tv.setTextColor(Color.WHITE);
}
}
com.actionbarsherlock.view.ActionMode contains method:
setTitle
It is used to change text near Close Icon in the ActionBar.
ActionMode is available in your com.actionbarsherlock.view.ActionMode.Callback interface implementation methods, like onCreateActionMode.
What you can do - is save incoming ActionMode reference and use it later to change title as your like. Or, if it is not dynamic - you can setup at with your constant in onCreateActionMode.
I have a field where the user can type a search query in the action bar of the application. This is declared in the action bar using a menu inflate in the Activity:
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
>
<item
android:id="#+id/action_search"
android:showAsAction="ifRoom"
android:actionViewClass="android.widget.SearchView"
android:title="#string/search"
></item>
</menu>
I need to customize the appearance of the SearchView (for instance background and text color). So far I could not find a way to do it using XML (using styles or themes).
Is my only option to do it in the code when inflating the menu?
Edit #1: I have tried programmatically but I cannot get a simple way to set the text color. Plus when I do searchView.setBackgroundResource(...) The background is set on the global widget, (also when the SearchView is iconified).
Edit #2: Not much information on the Search Developer Reference either
Seibelj had an answer that is good if you want to change the icons. But you'll need to
do it for every API version. I was using ICS with ActionBarSherlock and it didn't do justice for me but it did push me in the correct direction.
Below I change the text color and hint color. I showed how you might go about changing the
icons too, though I have no interest in that for now (and you probably want to use the default icons anyways to be consistent)
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Set up the search menu
SearchView searchView = (SearchView)menu.findItem(R.id.action_search).getActionView();
traverseView(searchView, 0);
return true;
}
private void traverseView(View view, int index) {
if (view instanceof SearchView) {
SearchView v = (SearchView) view;
for(int i = 0; i < v.getChildCount(); i++) {
traverseView(v.getChildAt(i), i);
}
} else if (view instanceof LinearLayout) {
LinearLayout ll = (LinearLayout) view;
for(int i = 0; i < ll.getChildCount(); i++) {
traverseView(ll.getChildAt(i), i);
}
} else if (view instanceof EditText) {
((EditText) view).setTextColor(Color.WHITE);
((EditText) view).setHintTextColor(R.color.blue_trans);
} else if (view instanceof TextView) {
((TextView) view).setTextColor(Color.WHITE);
} else if (view instanceof ImageView) {
// TODO dissect images and replace with custom images
} else {
Log.v("View Scout", "Undefined view type here...");
}
}
adding my take on things which is probably a little more efficient and safe across different android versions.
you can actually get a numeric ID value from a string ID name. using android's hierarchyviewer tool, you can actually find the string IDs of the things you are interested in, and then just use findViewById(...) to look them up.
the code below sets the hint and text color for the edit field itself. you could apply the same pattern for other aspects that you wish to style.
private static synchronized int getSearchSrcTextId(View view) {
if (searchSrcTextId == -1) {
searchSrcTextId = getId(view, "android:id/search_src_text");
}
return searchSrcTextId;
}
private static int getId(View view, String name) {
return view.getContext().getResources().getIdentifier(name, null, null);
}
#TargetApi(11)
private void style(View view) {
ImageView iv;
AutoCompleteTextView actv = (AutoCompleteTextView) view.findViewById(getSearchSrcTextId(view));
if (actv != null) {
actv.setHint(getDecoratedHint(actv,
searchView.getContext().getResources().getString(R.string.titleApplicationSearchHint),
R.drawable.ic_ab_search));
actv.setTextColor(view.getContext().getResources().getColor(R.color.ab_text));
actv.setHintTextColor(view.getContext().getResources().getColor(R.color.hint_text));
}
}
You can use the attribute android:actionLayout instead which lets you specify a layout to be inflated. Just have a layout with your SearchView and you won't have to modify anything really.
As to changing text style on the SearchView that is probably not possible as the SearchView is a ViewGroup. You should probably try changing text color via themes instead.
In case anyone wants to modify the views directly, here is how you can change the colors/fonts/images and customize the search box to your pleasure. It is wrapped in a try/catch in case there are differences between versions or distributions, so it won't crash the app if this fails.
// SearchView structure as we currently understand it:
// 0 => linearlayout
// 0 => textview (not sure what this does)
// 1 => image view (the search icon before it's pressed)
// 2 => linearlayout
// 0 => linearlayout
// 0 => ImageView (Search icon on the left of the search box)
// 1 => SearchView$SearchAutoComplete (Object that controls the text, subclass of TextView)
// 2 => ImageView (Cancel icon to the right of the text entry)
// 1 => linearlayout
// 0 => ImageView ('Go' icon to the right of cancel)
// 1 => ImageView (not sure what this does)
try {
LinearLayout ll = (LinearLayout) searchView.getChildAt(0);
LinearLayout ll2 = (LinearLayout) ll.getChildAt(2);
LinearLayout ll3 = (LinearLayout) ll2.getChildAt(0);
LinearLayout ll4 = (LinearLayout) ll2.getChildAt(1);
TextView search_text = (TextView) ll3.getChildAt(1);
search_text.setTextColor(R.color.search_text);
ImageView cancel_icon = (ImageView)ll3.getChildAt(2);
ImageView accept_icon = (ImageView)ll4.getChildAt(0);
cancel_icon.setBackgroundDrawable(d);
accept_icon.setBackgroundDrawable(d);
} catch (Throwable e) {
Log.e("SearchBoxConstructor", "Unable to set the custom look of the search box");
}
This example shows changing the text color and the background colors of the cancel/accept images. searchView is a SearchView object already instantiated with it's background color:
Drawable d = getResources().getDrawable(R.drawable.search_widget_background);
searchView.setBackgroundDrawable(d);
Here is the drawable code:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#color/white" />
</shape>
Obviously, this is hacky, but it will work for now.
From ICS this is doable using themes and styles. I'm using ActionBarSherlock which makes it applicable also for HC and below.
Add a style to define "android:textColorHint":
<style name="Theme.MyHolo.widget" parent="#style/Theme.Holo">
<item name="android:textColorHint">#color/text_hint_corp_dark</item>
</style>
Apply this as "actionBarWidgetTheme" to your theme:
<style name="Theme.MyApp" parent="#style/Theme.Holo.Light.DarkActionBar">
...
<item name="android:actionBarWidgetTheme">#style/Theme.MyHolo.widget</item>
</style>
Presto! Make sure that you use getSupportActionBar().getThemedContext() (or getSupportActionBar() for ActionBarSherlock) if any widgets are initiated where you might have other themes in effect.
How do you inflate the menu xml in your Activity? if you inflate the menu by using getMenuInflator() in your Activity, then the menu and also the searchView get the themed context, that have attached to the activity.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater.inflate(R.menu.search_action_menu, menu);
}
if you check the source code of Activity.getMenuInflator() at API-15, you can see the themed context codes. Here it is.
*/
public MenuInflater getMenuInflater() {
// Make sure that action views can get an appropriate theme.
if (mMenuInflater == null) {
initActionBar();
if (mActionBar != null) {
mMenuInflater = new MenuInflater(mActionBar.getThemedContext());
} else {
mMenuInflater = new MenuInflater(this);
}
}
return mMenuInflater;
}