Android: setting maxHeight parameter programmatically for ProgressBar/SeekBar - android

One can create a SeekBar in XML as follows...
<SeekBar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/bpseekbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:max="100"
android:maxHeight="8dp"
...
Now I want to do this programmatically since I need to adjust maxHeight based on screen resolution (yes, I know one shouldn't do that, but I have my valid reasons for this). I have no problems with setting the parameters programmatically except that I can't find out how to set maxHeight. I feel like I need to use Attributes but I couldn't find exactly how. Any hints?

It's not directly possible. SeekBar (actually ProgressBar which SeekBar extends) gets maxHeight only from XML layout attributes, there's no corresponding method.
Additionally, ProgressBar increases its maxHeight in call to setProgressDrawable to be at least height of the drawable. You may utilize this.
Another possibility is to extend SeekBar and provide own onMeasure method. This is actually where maxHeight is used. You can then use your extended SeekBar in xml layout.

The best way to set the maxHeight of seekBar programmatically is to use the fourth constructor SeekBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes), follow steps below:
define a style in values/style.xml;
<style name="SeekBarDefaultStyle">
<item name="android:maxHeight">1dp</item>
<item name="android:indeterminateOnly">false</item>
<item name="android:focusable">true</item>
<item name="android:mirrorForRtl">true</item>
</style>
construct the SeekBar like this: mSeekBar = new SeekBar(context, null, 0, R.style.SeekBarDefaultStyle);
BTW, google decides to support the method of setMaxHeight in API 29: https://developer.android.com/reference/android/widget/ProgressBar.html#setMaxHeight(int)

Related

Adding theme to Seekbar programmatically makes Seekbar disappear

I need to add a variable number of Seekbars depending on configuration.
for(int i=0;i<length;i++){
seeks[i] = new SeekBar(getActivity());
seeks[i].setMax(4);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(30,30,30,30);
seeks[i].setLayoutParams(layoutParams);
ll.addView(seeks[i]);
seeks[i].setVisibility(View.VISIBLE);
Works perfectly, but I would like the Seekbar to be discrete. In XML you can just add:
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/Base.Widget.AppCompat.SeekBar.Discrete"/>
However, if I follow the Docs, you should be able to add a Theme in the Seekbar constructor like so:
seeks[i] = new SeekBar(getActivity(), null, R.style.myTheme2 );
where I have set the theme in the styles.xml, OR
seeks[i] = new SeekBar(getActivity(), null, R.style.Widget_AppCompat_SeekBar_Discrete);
However, as soon as I do either of those things, the Seekbar disappears from view completely.
Got it working, leaving up for others who have the same problem, as I couldn't find it anywhere:
First setup a layout for each individual SeekBar:
seekbar_base.xml
<?xml version="1.0" encoding="utf-8"?>
<SeekBar
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:progressBackgroundTint="#color/seekBarBackground"
android:progressTint="#color/seekBarProgress"
android:thumbTint="#color/seekBar"
android:paddingLeft="20sp"
android:paddingTop="3dp"
android:paddingRight="20dp"
android:paddingBottom="30dp"
android:theme="#style/Widget.AppCompat.SeekBar.Discrete" />
Then instantiate it like so:
SeekBar bar = (SeekBar)LayoutInflater.from(getActivity()).inflate(R.layout.seekbar_base, null);
I still have no idea why it didn't work the way the docs said it should, but oh well.
when you use the XML, it actually set some default attribute. it is located in core / res / res / values / styles.xml
<style name="Widget.SeekBar">
<item name="android:indeterminateOnly">false</item>
<item name="android:progressDrawable">#android:drawable/progress_horizontal</item>
<item name="android:indeterminateDrawable">#android:drawable/progress_horizontal</item>
<item name="android:minHeight">20dip</item>
<item name="android:maxHeight">20dip</item>
<item name="android:thumb">#android:drawable/seek_thumb</item>
<item name="android:thumbOffset">8dip</item>
<item name="android:focusable">true</item>
</style>
at the same time, the SeekBar(Context context) also use the defalut style. it relaize that by call the same method you called, but set a defalut style.
public SeekBar(Context context) {
this(context, null);
}
public SeekBar(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.seekBarStyle);
}
so change your theme extends it.the add your custom item.
seeks[i] = new SeekBar(getActivity(), null, R.style.Widget_AppCompat_SeekBar_Discrete);
here are the document descirbe for three params constructor:
Perform inflation from XML and apply a class-specific base style from a
theme attribute. This constructor of View allows subclasses to use their
own base style when they are inflating. For example, a Button class's
constructor would call this version of the super class constructor and
supply R.attr.buttonStyle for defStyleAttr; this
allows the theme's button style to modify all of the base view attributes
(in particular its background) as well as the Button class's attributes.

Error applying image style dynamically, why?

attrs.xml:
<declare-styleable name="AppTheme">
<attr name="actionbarCompatLogoStyle" format="reference" />
</declare-styleable>
styles.xml:
<style name="Theme.MyApp" parent="android:style/Theme.Light">
<item name="actionbarCompatLogoStyle">#style/ActionBarCompatLogo</item>
</style>
<style name="ActionBarCompatLogo">
<item name="android:layout_width">30dp</item><!-- original image is huge -->
<item name="android:layout_height">30dp</item>
<item name="android:src">#drawable/app_logo</item>
</style>
Problem: if I use this, image dimensions won't work (huge image):
ImageButton logo = new ImageButton(context, null, R.attr.actionbarCompatLogoStyle);
If I use this, it works (tiny image, which is what I want):
<ImageView style="#style/ActionBarCompatLogo"></ImageView>
Why?
Any attribute prefixed with layout_ is part of a LayoutParams object. LayoutParams are special arguments to the parent view about how it should lay out the child view. The type of LayoutParams you set on a view is dependent on what type of ViewGroup you are adding it to. Each container view type can be different and so can the LayoutParams. layout_weight is specific to LinearLayout, layout_below is for RelativeLayout, etc. layout_width and layout_height are part of the base ViewGroup LayoutParams.
The takeaway from this is that LayoutParams are not parsed by the view's constructor, they're parsed by another step that your code above isn't doing. (The LayoutInflater involves the parent ViewGroup's generateLayoutParams method.)
Since LayoutParams are dependent on the intended parent of the View it's not recommended to put LayoutParams in styles. It mostly works when you are inflating views from layout XML but it has other implications similar to the edge case you've found here and requires you to be aware of them. For example, a style may specify layout_weight for a LinearLayout but if a view with that style is added to a RelativeLayout instead it will not behave as expected since RelativeLayout does not support layout_weight.
As far as I know it's not possible to apply styles to specific views programmatically, only via XML.
What you can do is to set a theme on your activity inside the onCreate() method. Consult this question: android dynamically change style at runtime

Android : set TextView style at runtime

Does any body know how to set style for TextView at run time:
something like this
myTextView.setStyle(R.style.mystyle);
Very easy just use setTextApparence and your style
myTextView.setTextAppearance(getApplicationContext(), R.style.boldText);
you will have to manually set each element of the style that you change, there is no way to setStyle at run time, AFAIK.
myTextView.setTextAppearance
myTextView.setTextSize
myTextView.setTextColor
I also still did not find (sadly) a way to change Style at runtime.
If it is just about changing the checkbox appearance (as you mention in a comment of another answer), you can use this:
myCheckbox.setButtonDrawable(R.drawable.star_checkbox);
And have a star_checkbox.xml file in the drawable directory describing the checkbox background according to its states such as:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:state_focused="true"
android:drawable="#drawable/star_checkbox_checked_focused" />
<item android:state_checked="false" android:state_focused="true"
android:drawable="#drawable/checkbox_not_checked_focused" />
<item android:state_checked="false"
android:drawable="#drawable/checkbox_not_checked" />
<item android:state_checked="true"
android:drawable="#drawable/checkbox_checked" />
</selector>
Also you need the corresponding png files in you drawable directory.
I am trying myself to do a similar thing.
My reason is that I want to use a style from my own Theme, BUT my User Interface Layout is entirely generated in code( using a custom layout builder), without defining any widgets in XML. So I cannot set a style in the XML layout of my widget – there isn’t any XML layout.
I am thinking that I will be able to set this style in the code of my widget by using
TypedArray a =
context.obtainStyledAttributes(AttributeSet
set, int[] attrs, int defStyleAttr, int defStyleRes)
Here it seems (to me) that
AttributeSet set = null; because this is what the XML inflater would have provided.
int[] attrs = R.styleable.MyWidget; defines what attributes I want to look at.
int defStyleAttr = myWidgetStyle; which is a reference, defined in my Theme, to a style for MyWidget. These are both defined in XML files in res/values.
“myWidgetStyle” follows the pattern of name the android developers have used in their code.
defStyleRes = 0; I am hoping that I don’t need to think about this.
Then to get any property , such as a background color,
Color color = a.getColor(R.styleable.MyWidget_background, R.color.my_default);
a.recycle();
This does seem to work –so far anyway.
It seems that the android build system conveniently generates the correct index to use in a.getColor, and names it R.styleable.MyWidget_background . I didn’t make this name myself so Android must have done it using my XML for my styleable MyWidget.
I expect one can look up the correct index by searching the TypedArray for the required attribute , but that would be inefficient and the TypedArray looks like an unpleasant contraption to deal with. I would use a very long stick to poke it!
Don
TextView (Context context, AttributeSet attrs, int defStyle)
Although there is construction available but it seems its buggy, I tried this and found specified style won't apply on my view.
After searching further got this filed bug: http://code.google.com/p/android/issues/detail?id=12683
To workaround this issue I am using setBackgroundResource, setTextAppearance, etc methods dramatically :)

Set style for TextView programmatically

I'm trying to use the TextView constructor with style like this:
TextView myText = new TextView(MyActivity.this, null, R.style.my_style);
However, when I do this, the text view does not appear to take the style (I verified the style by setting it on a static object).
I've also tried using myText.setTextAppearance(MyActivity.this, R.style.my_style) but it also doesn't work.
I do not believe you can set the style programatically. To get around this you can create a template layout xml file with the style assigned, for example in res/layout create tvtemplate.xml as with the following content:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="This is a template"
style="#style/my_style" />
then inflate this to instantiate your new TextView:
TextView myText = (TextView)getLayoutInflater().inflate(R.layout.tvtemplate, null);
You can create a generic style and re-use it on multiple textviews like the one below:
textView.setTextAppearance(this, R.style.MyTextStyle);
Edit: this refers to the Context object.
You can pass a ContextThemeWrapper to the constructor like this:
TextView myText = new TextView(new ContextThemeWrapper(MyActivity.this, R.style.my_style));
You can set the style in the constructor (but styles can not be dynamically changed/set).
View(Context, AttributeSet, int) (the int is an attribute in the current theme that contains a reference to a style)
Answer from Romain Guy
reference
Parameter int defStyleAttr does not specifies the style. From the Android documentation:
defStyleAttr - An attribute in the current theme that contains a
reference to a style resource that supplies default values for the
view. Can be 0 to not look for defaults.
To setup the style in View constructor we have 2 possible solutions:
With use of ContextThemeWrapper:
ContextThemeWrapper wrappedContext = new ContextThemeWrapper(yourContext, R.style.your_style);
TextView textView = new TextView(wrappedContext, null, 0);
With four-argument constructor (available starting from LOLLIPOP):
TextView textView = new TextView(yourContext, null, 0, R.style.your_style);
Key thing for both solutions - defStyleAttr parameter should be 0 to apply our style to the view.
Dynamically changing styles is not supported (yet). You have to set the style before the view gets created, via XML.
When using custom views that may use style inheritance (or event styleable attributes), you have to modify the second constructor in order not to lose the style. This worked for me, without needing to use setTextAppearence():
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, attrs.getStyleAttribute());
}
The accepted answer was great solution for me. The only thing to add is about inflate() method.
In accepted answer all android:layout_* parameters will not be applied.
The reason is no way to adjust it, cause null was passed as ViewGroup parent.
You can use it like this:
View view = inflater.inflate(R.layout.view, parent, false);
and the parent is the ViewGroup, from where you like to adjust android:layout_*.
In this case, all relative properties will be set.
Hope it'll be useful for someone.
I met the problem too, and I found the way to set style programatically. Maybe you all need it, So I update there.
The third param of View constructor accepts a type of attr in your theme as the source code below:
public TextView(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.textViewStyle);
}
So you must pass a type of R.attr.** rather than R.style.**
In my codes, I did following steps:
First, customize a customized attr to be used by themes in attr.xml.
<attr name="radio_button_style" format="reference" />
Second, specific your style in your used theme in style.xml.
<style name="AppTheme" parent="android:Theme.Translucent">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
<item name="radio_button_style">#style/radioButtonStyle</item>
</style>
<style name="radioButtonStyle" parent="#android:style/Widget.CompoundButton.RadioButton">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">64dp</item>
<item name="android:background">#000</item>
<item name="android:button">#null</item>
<item name="android:gravity">center</item>
<item name="android:saveEnabled">false</item>
<item name="android:textColor">#drawable/option_text_color</item>
<item name="android:textSize">9sp</item>
</style>
At the end, use it!
RadioButton radioButton = new RadioButton(mContext, null, R.attr.radio_button_style);
the view created programatically will use the specified style in your theme.
You can have a try, and hope it can work for you perfectly.
We can use TextViewCompact.setTextAppearance(textView, R.style.xyz).
Android doc for reference.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
textView.setTextAppearance(R.style.yourStyle)
you can use Extension Functions kotlin
fun TextView.setStyle(#StyleRes resId: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setTextAppearance(resId)
} else {
setTextAppearance(context, resId)
}
}
I have only tested with EditText but you can use the method
public void setBackgroundResource (int resid)
to apply a style defined in an XML file.
Sine this method belongs to View I believe it will work with any UI element.
regards.

Width of a scroll bar in android

In my application scroll bar is just too skinny to use. Does anyone know how to change the width of this?
Looking around in the platform resource files, I found this in res/values/themes.xml under the main Theme:
<item name="scrollbarSize">10dip</item>
<item name="scrollbarThumbHorizontal">#android:drawable/scrollbar_handle_horizontal</item>
<item name="scrollbarThumbVertical">#android:drawable/scrollbar_handle_vertical</item>
So, it looks like if you create your own Theme, as described in the documentation, you can provide your own drawables for the scrollbars.
I do wonder what you mean by they are "too skinny to use". They aren't meant to be touched/dragged. They are meant for display, to show you your current position relative to the entire ScrollView.
Instead of creating your own theme dedicated to your ScrollView, you can set the android:scrollbarSize attribute.
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarSize="2dp" />

Categories

Resources