How to setTextSize (TextView) in dp using RemoteViews - android

RemoteViews allow me to setTextSize TextView like this:
views.setFloat(R.id.appwidget_text, "setTextSize", fontSize);
but only with one argument. It will set font size in sp. I dont want the text in my widget to be measured in sp.
I need use setTextSize with 2 arguments (txtView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, fontSize);) using remote views. Is it possible to do this?

Yes! you can use this
public void setTextViewTextSize (int viewId,
int units,
float size)
viewId int: The id of the view whose text size should change
units int: The units of size (e.g. COMPLEX_UNIT_SP)
size float: The size of the text
This method is only available since API level 16 (android 4.1)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
remoteViews.setTextViewTextSize(R.id.price, TypedValue.COMPLEX_UNIT_PX, 100f);
}
doc here: https://developer.android.com/reference/android/widget/RemoteViews.html#setTextViewTextSize(int,%20int,%20float)

Related

Set ascent, descent, baseline of text in TextView

I need two TextViews to have same baseline, ascent, bottom, descent values. Is it possible to change the FontMetrics of TextView after text has been drawn?
It is so late, but I also confronted with this issue, and I solve with some tricks. (just modify baseline, not ascent, descent or something)
note that fontMetrics' values(ascent, descent, bottom, top) are depend on textSize.
so we must use fontMetrics' values after view is drawn. (if it is autoSizing or something)
to do something after view drawn, using Sa Qada's answer
baseline is always 0. descent, ascent, top, bottom is relative values.
refer this Suragch's answer.
change fontMetrics' values does not affect to UI.
to set custom baseline(text position of textview), just use padding.
below code is align to baseline with two TextView.
// this is kotlin code, but I'm sure you can understand
// align textview2 to textview1's baseline
val tv1Baseline = tv1.paddingBottom + tv1.paint.fontMetrics.bottom
val tv2Baseline = tv2.paddingBottom + tv2.paint.fontMetrics.bottom
val newPaddingOffset = tv1Baseline - tv2Baseline
tv2.setPadding(tv2.paddingLeft, tv2.paddingTop, tv2.paddingRight,
tv2.paddingBottom + newPaddingOffset)
Here's solution to align baselines (note the difference from bottom in Suragch answer and definition of return value of TextView.getBaseline()) which alignes tv2 baseline to tv1s':
private void alignWeatherTextBaseline(View tv1, View tv2) {
int tv1Baseline = tv1.getTop() + tv1.getBaseline();
int tv2Baseline = tv2.getTop() + tv2.getBaseline();
int newPaddingOffset = tv1Baseline - tv2Baseline;
if (newPaddingOffset != 0) {
tv2.setPadding(tv2.getPaddingLeft(),
tv2.getPaddingTop(), tv2.getPaddingRight(),
tv2.getPaddingBottom() - newPaddingOffset);
}
}
Be aware of the following:
if multiline text is possible, you need to write proper getLastLineBaseline() and use it instead of standard getBaseline()
you can get invalid value (0 or -1) from getBaseline() if a view hasn't been layout yet

Setting font-size of a single word to fill the entire screen

Part of my app displays a single 5-character word in a TextView which should fill the entire screen. The questions listed below address this same issue:
How to adjust text font size to fit textview
Have TextView scale its font size to fill parent?
Text size and different android screen sizes
Auto-fit TextView for Android
However, since my case requires only one 5-character word to fill the entire screen, is there a simpler way to do this? If not, would it be practical to simply provide drawable resources (assuming that the 5-character word will always be the same)?
Thanks!
I'm going to give you some code which shows the exact opposite of what you requested. The code below shrinks a line of text until it fits within the desired area. But there is the basic idea: Get the paint of the textView and then measure it. Adjust the size and remeasure it e.g. textView.getPaint().measureText("Your text")
public static float calculateTextSizeToFit(TextView textView, String desiredText, int limitSpSize, float desiredTxtPxSize) {
Paint measurePaint = new Paint(textView.getPaint());
measurePaint.setTextSize(desiredTxtPxSize);
float pWidth = measurePaint.measureText(desiredText);
float labelWidth = textView.getWidth();
int maxLines = textView.getMaxLines();
while (labelWidth > 0 && pWidth/maxLines > labelWidth-20) {
float textSize = measurePaint.getTextSize();
measurePaint.setTextSize(textSize-1);
pWidth = measurePaint.measureText(desiredText);
if (textSize < TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, limitSpSize,
textView.getContext().getResources().getDisplayMetrics())) break;
}
return measurePaint.getTextSize();
}

Setting textSize programmatically

textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, getResources().getDimension(R.dimen.result_font));
The following code works, but the R.dimen.result_font is taken as a much bigger value than it really is. Its maybe about 18sp-22sp or 24sp according to the screen size ... But the size set here is at least about 50sp. Can someone please recommend something ?
You have to change it to TypedValue.COMPLEX_UNIT_PX because getDimension(id) returns a dimen value from resources and implicitly converted to px.
Java:
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimension(R.dimen.result_font));
Kotlin:
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
resources.getDimension(R.dimen.result_font))
Requirement
Suppose we want to set textView Size programmatically from a resource file.
Dimension resource file (res/values/dimens.xml)
<resources>
<dimen name="result_font">16sp</dimen>
</resources>
Solution
First get dimen value from resource file into a variable "textSizeInSp".
int textSizeInSp = (int) getResources().getDimension(R.dimen.result_font);
Next convert 16 sp value into equal pixels.
for that create a method.
public static float convertSpToPixels(float sp, Context context) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics());
}
Let's set TextSize,
textView.setTextSize(convertSpToPixels(textSizeInSp , getApplicationContext()));
All together,
int textSizeInSp = (int) getResources().getDimension(R.dimen.result_font);
textView.setTextSize(convertSpToPixels(textSizeInSp , getApplicationContext()));

Label Text size according to the screen size in a chart engine pie chart in android

I am successfully displaying pie chart using achart engine.I want to customize my labels text size according to the screen size.Thanks in advance.
This problem comes down to resolution. achartengine seems to have been designed with raw pixels in mind while display quality and pixel density has increased dramatically over the last couple years. The labels from the achartengine sample are tiny on my HTC One!
Android has introduced scale-independent pixels. The key to using them with achartengine is the TypedValue class. Here's what I did:
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
float val = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 18, metrics);
I got 18 from "text size medium" in the link above.
You can then use val anywhere you want to use medium sized text. For example:
renderer.setLabelsTextSize(val);
This a summarised version of what I did:
public static final int TEXT_SIZE_XHDPI = 24;
public static final int TEXT_SIZE_HDPI = 20;
public static final int TEXT_SIZE_MDPI = 18;
public static final int TEXT_SIZE_LDPI = 13;
XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
switch (getResources().getDisplayMetrics().densityDpi) {
case DisplayMetrics.DENSITY_XHIGH:
renderer.setMargins(new int[] { 40, 90, 25, 10 });
renderer.setAxisTitleTextSize(Constants.TEXT_SIZE_XHDPI);
renderer.setChartTitleTextSize(Constants.TEXT_SIZE_XHDPI);
renderer.setLabelsTextSize(Constants.TEXT_SIZE_XHDPI);
renderer.setLegendTextSize(Constants.TEXT_SIZE_XHDPI);
break;
case DisplayMetrics.DENSITY_HIGH:
renderer.setMargins(new int[] { 30, 50, 20, 10 });
renderer.setAxisTitleTextSize(Constants.TEXT_SIZE_HDPI);
renderer.setChartTitleTextSize(Constants.TEXT_SIZE_HDPI);
renderer.setLabelsTextSize(Constants.TEXT_SIZE_HDPI);
renderer.setLegendTextSize(Constants.TEXT_SIZE_HDPI);
break;
default:
renderer.setMargins(new int[] { 30, 50, 20, 10 });
renderer.setAxisTitleTextSize(Constants.TEXT_SIZE_LDPI);
renderer.setChartTitleTextSize(Constants.TEXT_SIZE_LDPI);
renderer.setLabelsTextSize(Constants.TEXT_SIZE_LDPI);
renderer.setLegendTextSize(Constants.TEXT_SIZE_LDPI);
break;
}
So I basically customised the margins and text sizes of the chart depending of the device's screen density. Note: I excluded the medium density case for now.
I wrote two methods called _dp and _sp to convert to dp and sp values.
private DisplayMetrics displayMetrics;
private boolean isPortrait;
int _dp(float pixels) {
return (int)(pixels * displayMetrics.density);
}
float _sp(float pixels) {
return (pixels * displayMetrics.scaledDensity);
}
In your onCreate you need to set the displayMetrics value:
displayMetrics = (this.getResources()).getDisplayMetrics();
Then you just use _sp and _dp to get the sp/dp value. For instance to set a font scaled to 18
renderer.setAxisTitleTextSize(_sp(18));
And to set margins with dp values:
renderer.setMargins(new int[] {_dp(25), _dp(30), _dp(35), _dp(20)});
NOTE: I made one change to this code. It is possible to get a 0 value for these functions -- which is a real problem if you are dividing by the return value. I added a test to return 1 if the return value is < 1. ie: return ((rv < 1) ? 1 : v);
You can set the labels text size this way:
renderer.setLabelsTextSize(size);
You will have to find the best logic for finding the best proportion between the screen size and the labels size.
The best practice is to place dummy TextView into layout to obtain the textSize:
<TextView
android:id="#+id/dummyTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:text="TextView" />
And in your code for example:
TextView testTextView = (TextView) rootView.findViewById(R.id.dummyTextView);
float textSize = testTextView.getTextSize();
renderer.setLabelsTextSize(textSize);
renderer.setLegendTextSize(textSize);
I think the best way to do it is to define sizes in the file dimens.xml in dp and sp like so:
<dimen name="graph_chart_text_size">16sp</dimen>
<dimen name="graph_axis_title_text_size">14sp</dimen>
<dimen name="graph_labels_text_size">12sp</dimen>
<dimen name="graph_labels_padding">5dp</dimen>
<dimen name="graph_legend_text_size">14sp</dimen>
<dimen name="graph_legend_height">40dp</dimen>
<dimen name="graph_point">3dp</dimen>
<dimen name="graph_line">3dp</dimen>
<dimen name="graph_margin_top">10dp</dimen>
<dimen name="graph_margin_left">40dp</dimen>
<dimen name="graph_margin_right">10dp</dimen>
<dimen name="graph_margin_bottom">20dp</dimen>
And then use getDimension and getDimensionPixelOffset to convert to pixels when configuring the renderer, such as:
renderer.setChartTitleTextSize(context.getResources().getDimension(R.dimen.graph_chart_text_size));
renderer.setAxisTitleTextSize(context.getResources().getDimension(R.dimen.graph_axis_title_text_size));
renderer.setLabelsTextSize(context.getResources().getDimension(R.dimen.graph_labels_text_size));
renderer.setLegendTextSize(context.getResources().getDimension(R.dimen.graph_legend_text_size));
renderer.setLegendHeight(context.getResources().getDimensionPixelOffset(R.dimen.graph_legend_height));
renderer.setMargins(new int[]{
context.getResources().getDimensionPixelOffset(R.dimen.graph_margin_top),
context.getResources().getDimensionPixelOffset(R.dimen.graph_margin_left_mood),
context.getResources().getDimensionPixelOffset(R.dimen.graph_margin_bottom),
context.getResources().getDimensionPixelOffset(R.dimen.graph_margin_right)});
}
I testing in phones that range from 800x480 to 1920x1080 and the design is very consistent.
You can try this:
renderer.setLegendTextSize(textSize);

What is the size of ActionBar in pixels?

I need to know the exact size of ActionBar in pixels so to apply correct background image.
To retrieve the height of the ActionBar in XML, just use
?android:attr/actionBarSize
or if you're an ActionBarSherlock or AppCompat user, use this
?attr/actionBarSize
If you need this value at runtime, use this
final TypedArray styledAttributes = getContext().getTheme().obtainStyledAttributes(
new int[] { android.R.attr.actionBarSize });
mActionBarSize = (int) styledAttributes.getDimension(0, 0);
styledAttributes.recycle();
If you need to understand where this is defined:
The attribute name itself is defined in the platform's /res/values/attrs.xml
The platform's themes.xml picks this attribute and assigns a value to it.
The value assigned in step 2 depends on different device sizes, which are defined in various dimens.xml files in the platform, ie. core/res/res/values-sw600dp/dimens.xml
From the de-compiled sources of Android 3.2's framework-res.apk, res/values/styles.xml contains:
<style name="Theme.Holo">
<!-- ... -->
<item name="actionBarSize">56.0dip</item>
<!-- ... -->
</style>
3.0 and 3.1 seem to be the same (at least from AOSP)...
To get the actual height of the Actionbar, you have to resolve the attribute actionBarSize at runtime.
TypedValue tv = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true);
int actionBarHeight = getResources().getDimensionPixelSize(tv.resourceId);
One of the Honeycomb samples refers to ?android:attr/actionBarSize
I needed to do replicate these heights properly in a pre-ICS compatibility app and dug into the framework core source. Both answers above are sort of correct.
It basically boils down to using qualifiers. The height is defined by the dimension "action_bar_default_height"
It is defined to 48dip for default. But for -land it is 40dip and for sw600dp it is 56dip.
If you're using the compatibility ActionBar from the recent v7 appcompat support package, you can get the height using
#dimen/abc_action_bar_default_height
Documentation
With the new v7 support library (21.0.0) the name in R.dimen has changed to #dimen/abc_action_bar_default_height_material.
When upgrading from a previous version of the support lib you should therefore use that value as the actionbar's height
If you are using ActionBarSherlock, you can get the height with
#dimen/abs__action_bar_default_height
#AZ13's answer is good, but as per the Android design guidelines, the ActionBar should be at least 48dp high.
Accepted answer in Kotlin :
val Context.actionBarSize
get() = theme.obtainStyledAttributes(intArrayOf(android.R.attr.actionBarSize))
.let { attrs -> attrs.getDimension(0, 0F).toInt().also { attrs.recycle() } }
Usage :
val size = actionBarSize // Inside Activity
val size = requireContext().actionBarSize // Inside Fragment
val size = anyView.context.actionBarSize // Inside RecyclerView ViewHolder
public int getActionBarHeight() {
int actionBarHeight = 0;
TypedValue tv = new TypedValue();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv,
true))
actionBarHeight = TypedValue.complexToDimensionPixelSize(
tv.data, getResources().getDisplayMetrics());
} else {
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,
getResources().getDisplayMetrics());
}
return actionBarHeight;
}
The Class Summary is usually a good place to start. I think the getHeight() method should suffice.
EDIT:
If you need the width, it should be the width of the screen (right?) and that can be gathered like this.
On my Galaxy S4 having > 441dpi > 1080 x 1920 >
Getting Actionbar height with getResources().getDimensionPixelSize I got 144 pixels.
Using formula px = dp x (dpi/160), I was using 441dpi, whereas my device lies
in the category 480dpi. so putting that confirms the result.
I did in this way for myself, this helper method should come in handy for someone:
private static final int[] RES_IDS_ACTION_BAR_SIZE = {R.attr.actionBarSize};
/**
* Calculates the Action Bar height in pixels.
*/
public static int calculateActionBarSize(Context context) {
if (context == null) {
return 0;
}
Resources.Theme curTheme = context.getTheme();
if (curTheme == null) {
return 0;
}
TypedArray att = curTheme.obtainStyledAttributes(RES_IDS_ACTION_BAR_SIZE);
if (att == null) {
return 0;
}
float size = att.getDimension(0, 0);
att.recycle();
return (int) size;
}

Categories

Resources