how to change number picker style in android? - android

I want to use the NumberPicker component-widget but Instead in the default Holo theme I need to replace the blue color with orange since that is the default color in my styling.
How can I replace the blue color and the color of the numbers,and keep all of the functionality of the component?
thanks

Unfortunately, you can't style it. The styles and styling attributes for NumberPicker are not present in the public API, therefore you can't set them and change the default look. You can only select between light and dark theme.
As a solution I would suggest to use android-numberpicker library instead. The library is basically a port of NumberPicker extracted from Android source codes. But it's better than that, it also backports NumberPicker to Android 2.x. The library can be easily styled.
To style the divider adjust NPWidget.Holo.NumberPicker style and its selectionDivider and selectionDividerHeight attributes.
To style the text adjust NPWidget.Holo.EditText.NumberPickerInputText style.

Preview of a customized number picker:
<NumberPicker
android:id="#+id/np"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerHorizontal="true"
android:background="#drawable/drawablenp"
android:layout_centerVertical="true"/>
Create the background xml in the drawable folder named "drawablenp.xml"
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#707070"
android:centerColor="#f8f8f8"
android:endColor="#707070"
android:angle="270"/>
</shape>

Make copy of library/res/drawable-*/numberpicker_selection_divider.9.png and name then, for example, custom_np_sd.9.png.
Override default NumberPicker style via activity theme:
<style name="AppTheme" parent="#style/Holo.Theme">
<item name="numberPickerStyle">#style/CustomNPStyle</item>
</style>
<style name="CustomNPStyle" parent="#style/Holo.NumberPicker">
<item name="selectionDivider">#drawable/custom_np_sd</item>
</style>
And apply #style/AppTheme as activity theme.

I faced this problem too. I really want to have nice NumberPicker UI. All answer in this question worked but very limited. I almost create my own RecylerView to create the NumberPicker I want. Apparently I found neat library which is very robust. Here is the link https://github.com/Carbs0126/NumberPickerView
Not trying to answer the question here. Just want to help someone with the same problem as I am.

I face this problem too, I use reflect to change the style
public class MyNumberPicker extends NumberPicker {
public MyNumberPicker(Context context) {
super(context);
setNumberPickerDivider();
}
public MyNumberPicker(Context context, AttributeSet attrs) {
super(context, attrs);
setNumberPickerDivider();
}
public MyNumberPicker(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setNumberPickerDivider();
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public MyNumberPicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setNumberPickerDivider();
}
#Override
public void addView(View child) {
super.addView(child);
updateView(child);
}
#Override
public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
super.addView(child, index, params);
updateView(child);
}
#Override
public void addView(View child, android.view.ViewGroup.LayoutParams params) {
super.addView(child, params);
updateView(child);
}
public void updateView(View view) {
if (view instanceof EditText) {
EditText et = (EditText) view;
et.setTextColor(ContextCompat.getColor(getContext(), R.color.font_content));
et.setTextSize(16);
}
}
private void setNumberPickerDivider() {
try {
{
Field field = NumberPicker.class.getDeclaredField("mSelectionDivider");
field.setAccessible(true);
field.set(this, ContextCompat.getDrawable(getContext(), R.drawable.horizontal_divider));
}
{
Field field = NumberPicker.class.getDeclaredField("mSelectionDividerHeight");
field.setAccessible(true);
field.set(this, 1);
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}

Related

Android Custom Icon Font only works if I call setTypeface after View is inflated

I have a custom font file, say myfont.ttf in assets/fonts/
I have created a custom View like this
public class IconFontView extends AppCompatTextView {
public IconFontView(Context context) {
super(context);
applyIconFonts(context);
}
public IconFontView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
applyIconFonts(context);
}
public IconFontView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
applyIconFonts(context);
}
private void applyIconFonts(final Context context) {
final Typeface iconFont = Typeface.createFromAsset(context.getAssets(), "fonts/myfont.ttf");
setTypeface(iconFont);
}
}
in XML:
<com.smule.singandroid.customviews.IconFontView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="400dp"
android:text="#string/icontext"/> <!-- my unicode for the specific icon -->
strings.xml:
<string name="icontext"></string>
This way, I can see the preview perfectly fine.
But, if I enter this fragment, I see nothing but an empty view. (using "Show layout bounds" to tell you that this view exists there, just not drawing)
HOWEVER, if I add this font to my styles.xml like this
<style name="IconFont">
<item name="fontPath">fonts/myfont.ttf</item>
</style>
and apply it in layout xml like this
<com.smule.singandroid.customviews.IconFontView
style="#style/IconFont"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="400dp"
android:text="#string/icontext"/> <!-- my unicode for the specific icon -->
This not only displays correct preview, but also shows the icon perfectly fine.
This has same effect as doing something like
mIconFontview.setText(R.string.icontext);
mIconFontView.setTypeFace(...);
Why would this work this way?
Then there would be no reason to create IconFontView at all. Might as well just use TextView.

How to apply theme programmatically on all buttons?

Here is my button:
public class ChimmerButton extends Button {
public ChimmerButton(Context context) {
super(context);
}
public ChimmerButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ChimmerButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/*
* This method is used to apply the external font
*/
public void setTypeface(Typeface tf, int style) {
if (!isInEditMode()) {
super.setTypeface(Typeface.createFromAsset(
getContext().getAssets(), "calibre-regular.ttf"));
}
}
}
How can i apply Theme.Light.NoTitleBar.Fullscreen on all chimmerButtons using above code?? Is there any solution for this?
Note that this should be called before any views are instantiated in
the Context (for example before calling setContentView(View) or
inflate(int, ViewGroup)).
from:
http://developer.android.com/reference/android/view/ContextThemeWrapper.html#setTheme%28int%29
Unfortunately, You must set the theme before displaying the Activity at all.
Therefore you can't have 'dynamic' themes driven by runtime code (though the comment above shows how to make a custom theme for your buttons)
ContextThemeWrapper themedContext;
public ChimmerButton(ContextThemeWrapper themedContext) {
This.themedContext = themedContext;
}
if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
themedContext = new ContextThemeWrapper( Activity.this, android.R.style.Theme_Holo_Light_Dialog_NoActionBar );
}
else {
themedContext = new ContextThemeWrapper( Activity.this, android.R.style.Theme_Light_NoTitleBar );
Button's theme is context dependent by default. So instead of setting theme for buttons, set theme for the activity that contains the button. It is a much easier solution.
Apply a theme to an activity in Android?

Extending Preference classes in Android Lollipop = losing animation

Just for extending CheckBoxPreference or SwitchPreference on Android Lollipop, the widget (the checkbox or the switch) won't have animation anymore.
I'd like to extend SwitchPreference to force api < 21 to use SwitchCompat instead of the default one they are using (which is obviously wrong).
I am using the new AppCompatPreferenceActivity with appcompat-v7:22.1.1 but that doesn't seem to affect the switches.
The thing is that with just extending those classes, without adding any custom layout or widget resource layout, the animation is gone.
I know I can write two instances of my preference.xml (on inside values-v21) and it will work... But I'd like to know why is this happening and if somebody knows a solution without having two preference.xml.
Code example:
public class SwitchPreference extends android.preference.SwitchPreference {
public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public SwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SwitchPreference(Context context) {
super(context);
}
}
This or the same for CheckBoxPreference and then using:
<com.my.package.SwitchPreference />
Will make the animation in a Lollipop device to be gone.
--
Another thing I tried for the SwitchPreference (that I can with CheckBoxPreference) is to give a layout with the default id but #android:id/switchWidgetis not public while #android:id/checkbox is. I also know I can use a <CheckBoxPreference /> and give a widget layout that is in fact a SwitchCompat, but I'd like to avoid that (confusing the names).
It seems I found a fix for your issue.
Extensive Explanation
In SwitchCompat, when toggling the the switch, it tests a few functions before playing the animation: getWindowToken() != null && ViewCompat.isLaidOut(this) && isShown().
Full method:
#Override
public void setChecked(boolean checked) {
super.setChecked(checked);
// Calling the super method may result in setChecked() getting called
// recursively with a different value, so load the REAL value...
checked = isChecked();
if (getWindowToken() != null && ViewCompat.isLaidOut(this) && isShown()) {
animateThumbToCheckedState(checked);
} else {
// Immediately move the thumb to the new position.
cancelPositionAnimator();
setThumbPosition(checked ? 1 : 0);
}
}
By using a custom view extending SwitchCompat, I found out, that isShown() always returns false, because the at third iteration of the while, parent == null.
public boolean isShown() {
View current = this;
//noinspection ConstantConditions
do {
if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) {
return false;
}
ViewParent parent = current.mParent;
if (parent == null) {
return false; // We are not attached to the view root
}
if (!(parent instanceof View)) {
return true;
}
current = (View) parent;
} while (current != null);
return false;
}
Interestingly, the third parent is the second attribute passed to getView(View convertView, ViewGroup parent) in Preference, means the PreferenceGroupAdapter didn't get a parent passed to its own getView(). Why this happens exactly and why this happens only for custom preference classes, I don't know.
For my testing purposes, I used the CheckBoxPreference with a SwitchCompat as widgetLayout, and I also didn't see animations.
Fix
Now to the fix: simply make your own view extending SwitchCompat, and override your isShown() like this:
#Override
public boolean isShown() {
return getVisibility() == VISIBLE;
}
Use this SwitchView for your widgetLayout style, and animations work again :D
Styles:
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
…
<item name="android:checkBoxPreferenceStyle">#style/Preference.SwitchView</item>
…
</style>
<style name="Preference.SwitchView">
<item name="android:widgetLayout">#layout/preference_switch_view</item>
</style>
Widget layout:
<de.Maxr1998.example.preference.SwitchView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#null"
android:clickable="false"
android:focusable="false" />
Sometimes Extending from a Class is not the best solution. To avoid loosing the animations you could instead Compose it, I meant creating a Class where you have a SwitchPreference field variable and apply the new logic to it. It's like a wrapper. This worked for me.
i manage to fix it like this and animations is working before it was going to the state directly without animation:
FIX:
CustomSwitchCompat.class
public class CustomSwitchCompat extends SwitchCompat {
public CustomSwitchCompat(Context context) {
super(context);
}
public CustomSwitchCompat(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomSwitchCompat(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public boolean isShown() {
return getVisibility() == VISIBLE;
}
}
In your layout do this: preference_switch_layout.xml
<com.example.CustomSwitchCompat
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#null"
android:clickable="false"
android:focusable="false"
app:switchMinWidth="55dp"/>
and in your preference.xml do this:
<CheckBoxPreference
android:defaultValue="false"
android:key=""
android:widgetLayout="#layout/preference_switch_layout"
android:summary=""
android:title="" />
I was having this issue, when I was using custom layout (app:layout) for SwitchPreference. At first, switch animation was triggered, but after a little scrolling it stopped and switch was jumping without animation. I tried every solution from stackoverflow, but nothing helped.
After debugging of SwitchCompat.setChecked method I found out that this condition is failing:
public void setChecked(boolean checked) {
...
if (getWindowToken() != null && ViewCompat.isLaidOut(this)) {
animateThumbToCheckedState(checked);
} else {
// Immediately move the thumb to the new position.
cancelPositionAnimator();
setThumbPosition(checked ? 1 : 0);
}
}
Concretely ViewCompat.isLaidOut(this) returned false. I guess this is a bug either in View or Preference (or subclasses). Anyway, I was able to fix this with little hack.
I created a subclass of SwitchCompat and did override setChecked method, where I call requestLayout() and in onNextLayout I call SwitchCompat's setChecked method. This guarantees that isLaidOut condition is true when changing checked state.
Full code of custom SwitchCompat:
class SwitchCompatFix #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = androidx.appcompat.R.attr.switchStyle,
): SwitchCompat(context, attrs, defStyleAttr) {
override fun setChecked(checked: Boolean) {
doOnNextLayout {
post { super.setChecked(checked) }
}
requestLayout()
}
}
public class SwitchPreference extends android.preference.SwitchPreference {
public SwitchPreference(Context context) {
this(context, null);
}
public SwitchPreference(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.checkBoxPreferenceStyle);
}
public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
try {
Field canRecycleLayoutField = Preference.class.getDeclaredField("mCanRecycleLayout");
canRecycleLayoutField.setAccessible(true);
canRecycleLayoutField.setBoolean(this, true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}

Custom Preference Category won't show Text title

I'm trying to get my Preference category header to be consistent with the theme of my app, so after searching around both on SO and some blogs I follow..I found the best(and easiest) way was just to create a custom Preference Category class that overrides onCreateView() or onBindView() and programmatically set the color of the category TextView and it's background. Sounds easy enough.
My only two caveats is that I'm using a SherlockPreferenceActivity, and therefore I'm not able to simply apply a custom theme to my Activity since I have to use a Sherlock theme or a derivative. Also, my other thing(and I think this may be the cause) is that I'm trying to set the TextView's background to a Shape Drawable, which is a gradient with a stroke in xml. The background of the preference category changes just fine, but I don't see any TextView at all, which leads to me to think that maybe the background is being drawn on top of it's textView? I'm not sure
Here's the code for my CustomPreferenceCategory class. As you can see I tried it both using onBindView() and onCreateView().
public class CustomPreferenceCategory extends PreferenceCategory {
public CustomPreferenceCategory(Context context) {
super(context);
}
public CustomPreferenceCategory(Context context, AttributeSet attrs) {
super(context);
}
public CustomPreferenceCategory(Context context, AttributeSet attrs,
int defStyle) {
super(context);
}
#Override
protected void onBindView(View view) {
super.onBindView(view);
TextView titleView = (TextView) view.findViewById(android.R.id.title);
titleView.setBackgroundResource(R.drawable.header_non_rounded);
titleView.setTextColor(Color.WHITE);
}
//#Override
/*protected View onCreateView(ViewGroup parent) {
// And it's just a TextView!
TextView categoryTitle = (TextView) super.onCreateView(parent);
categoryTitle.setBackgroundResource(R.drawable.header_non_rounded);
categoryTitle.setTextColor(Color.WHITE);
return categoryTitle;
}*/
}
Here's how I'm setting it via my preferences.xml file
<com.brightr.weathermate.views.CustomPreferenceCategory android:title="Weather" >
<CheckBoxPreference
android:defaultValue="true"
android:key="degreesC"
android:summary="Display the weather degrees in Celsius units"
android:title="Show Celsius" />
<CheckBoxPreference
android:defaultValue="true"
android:key="degreesF"
android:summary="Display the weather in Farenheit units"
android:title="Show Farenheit" />
<ListPreference
android:entries="#array/textColors"
android:entryValues="#array/textColor_values"
android:summary="Change the color of the temerature text"
android:title="Temperature Text Color" />
</com.brightr.weathermate.views.CustomPreferenceCategory>
Any thoughts as to why only the background is being changed but the TextView is not visible? Also, even when I use setBackgroundResource() instead of setBackgroundDrawable(), it still doesn't set the text. Any help would be greatly appreciate guys.
Got it. Silly me, I forgot to pass in the other two params in each of the constructors. I feel like kicking myself.
public CustomPreferenceCategory(Context context) {
super(context);
}
public CustomPreferenceCategory(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomPreferenceCategory(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}

Difference between a clickable ImageView and ImageButton

I'm just wondering if there is any significant difference between an ImageView that's set to be clickable, compared with an ImageButton?
Is there any reason for using one over the other? Is there any restriction on the drawable for an ImageButton that leaves ImageView as the only possible option?
Will I possibly lose any functionality of a button if I opt for a clickable ImageView over ImageButton?
There's no differences, except default style. ImageButton has a non-null background by default.
EDIT: Also, ImageButton.onSetAlpha() method always returns false, scaleType is set to center and it's always inflated as focusable.
Here's ImageButton's default style:
<style name="Widget.ImageButton">
<item name="android:focusable">true</item>
<item name="android:clickable">true</item>
<item name="android:scaleType">center</item>
<item name="android:background">#android:drawable/btn_default</item>
</style>
ImageButton is inherited from ImageView
public class ImageButton extends ImageView {
public ImageButton(Context context) {
this(context, null);
}
public ImageButton(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.imageButtonStyle);
}
public ImageButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setFocusable(true);
}
#Override
protected boolean onSetAlpha(int alpha) {
return false;
}
#Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(ImageButton.class.getName());
}
#Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(ImageButton.class.getName());
}
as #Micheal describe i just add details to his answer
The effect of a button click when I click is there for imagebutton but not for imageView.
If you want, you can give the button clic effect as a background. ImageButton has an effect by default.

Categories

Resources