Autoresizing of text in Android - android

In iOS there is a notion of UIView's being able to resize themselves based on constraints given by the parent View. For example, if the parent View enlarges itself, then the child Views might expand or shrink to fit the available space. This is built in to the platform and makes development trivial.
So, my problem is that I am developing a smartphone application that makes use of the ActionBar in ICS. I have a custom view in there that I set using:
actionBar.setCustomView(R.layout.my_custom_title);
Note that I'm just inflating a view from the xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/title"
style="#style/TextAppearance.Title.Theme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:scrollHorizontally="true"
android:singleLine="true"
android:text="Title" />
<TextView
android:id="#+id/subtitle"
style="#style/TextAppearance.SubTitle.Theme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:scrollHorizontally="true"
android:singleLine="true"
android:text="Subtitle" />
</LinearLayout>
Now, in ICS, the ActionBar changes its height during an orientation change. It is narrower in landscape mode than in portrait mode. This causes my "subtitle" text to be cut off in landscape mode since the height of the ActionBar has shrunk, while my custom title view text has not resized itself.
Is it possible to resize the text on orientation change without programmatically doing so?
I'm overring
onConfigurationChanged()
so I can't just have a separate landscape and portrait custom title view.
SIDE NOTE:
This reminds me... I wish in the onConfigurationChanged() we can just supply a new xml layout that basically just adjusts the positioning of the views on the screen. The portrait and xml layouts would have to contain the same views of course, but there would be different layout information. This would make life much easier and would be more efficient than having onCreate() called again.

Your TextView has changed its size but the text size has not changed. There is no way to change the text size without some extra effort but you have different options:
you define different text size values for portrait and landscape mode and dont override onConfigurationChanged. This can by done by creating two dimensions.xml. One is inside res/values-land and the other in res/values-port
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="font_size">16dp</dimen>
</resources>
And in your layout assign that value to your TextView
<TextView
android:textSize="#dimen/font_size"
Second option is to compute the font size programatically. This was already covered in another question

Related

How to specify Custom Tab View without an image?

I have created a layout XML and called setCustomTabView in the right sequence and verified that it's pretty much as described here.
How can custom tab view be implemented using setCustomTabView method in SlidingTabColor sample?
I don't want an image. I only want to control the text size. I want the default on a small phone, but twice the size on a tablet. The default is very small on a tablet. The app is used outdoors and visibility and large buttons is important. I have two "buckets" so far. The following examples are for the default.
If I use this xml layout, I only see the text for the first tab, and no colorizer.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Default sized TextView for tab title.
This allows us to specify a larger one for tablets in layout-w720dp. -->
<TextView
android:id="#+id/tab_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="18dp"/>
</LinearLayout>
If I add the xml for an image and provide a source, it works. If I leave out the source, the result is the same as for a layout with only a TextView.
<TextView
android:id="#+id/tab_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="18dp"/>
<ImageView
android:layout_width="wrap_content"
android:src="#drawable/ic_launcher"
android:layout_height="wrap_content" />
In one of my experiments I increased the text size (very large) and without an image I got all four tab titles.
How can I replicate the default tab titles with only a TextView?
(I had a working solution where I detected the metrics at run time and doubled the text size, but I want to control this through different layout subfolders.)
I see that the default tabView is a simple, instantiated TextView and tabTitleView is equated to it. If I could do a findViewByIdon the TextView within my layout I could do the same. But attempts to do that resulted in a null TextView - probably because a ViewGroup is not yet established. But if I use my layout the child already has a parent and can't be used in the tab strip's addView().
This worked.
<TextView
android:id="#+id/tab_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="12sp"
android:gravity="center_vertical|center_horizontal"
android:padding="16dp" />
Using the debugger (and looking at the source where the default tabView is created) I saw that gravity was 0x800033 for my TextView and 0x000011 for theirs. Changing the android:gravity and adding the same padding as the default fixed it. I think center would also work. It's an alias for vertical|horizontal (1<<4|1<<0).
I also called setAllCaps(true) on the tabTitleView for consistency.

Android RTL layout direction align center issue

I'm developing an Android App that needs to be support Arabic language. (Which should be read from Right To Left). After quick googled the solutions, I figure out android fully support Arabic language natively in API level 17 with the declaration of
android:supportsRtl="true"
in the application tag inside of the AndroidManifest so that I can use the layout mirroring to automatically flip the layout for better right to left reading experience. However, I've noticed there is an issue happening while I use centerInParent in a view that inside of a sub RelativeLayout during the layout mirroring. Below are my codes and expected layout.
<RelativeLayout
android:background="#color/white"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:padding="20dp">
<RelativeLayout
android:background="#drawable/shape_flag_imageview_boarder"
android:id="#+id/imageLayout"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
<ImageView
android:id="#+id/image"
android:layout_height="100dp"
android:layout_width="100dp"
android:visibility="invisible" />
<ProgressBar
android:id="#+id/progressbar"
android:layout_centerInParent="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
</RelativeLayout>
<TextView
android:id="#+id/text"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_toEndOf="#id/imageLayout"
android:layout_width="wrap_content"
android:text="Some text here bla bla bla"
android:textColor="#color/black" />
</RelativeLayout>
Image above showing the expected result in normal layout direction which is Left to Right. The purpose I wrap the ImageView and ProgressBar together in a sub view is because I want the ProgressBar showing in the middle of the ImageView while the image is loading from the internet. After the I've changed Locale to Arabic, it becomes like
As I've try and error and figure out that this is causing by the centerInParent of the ProgressBar. It instead of centering inside the sub view, it align center to the root parent view which is the most outer RelativeLayout. Below is the screen shot of removing centerInParent code from the ProgressBar.
It clearly shows the layout mirroring works good, but the ProgressBar position is not what I'm expected. So I've try to work on centerVertical and centerHorizontal, the result are shown in images below respectively.
None of the solutions works, and none of the topic I've searched related to this issue. So I guess this might be a bug from Android library? If anyone knows the issues or solutions, please share to me. Thanks
I fixed it by adding android:layoutDirection="ltr" into the child RelativeLayout. Basically, it deactivates the RTL formatting for this particular RelativeLayout, and the android:layout_centerInParent="true" behaves correctly again. It solves our particular issue as our particular RelativeLayout contains only centred elements. But this trick should not be used if the Layout contains other elements which have to support correctly RTL, like text views for example. Hope it helps.
This is an RTL layout bug in the Android framework, which only affects Android 4.2 specifically (API 17) and when android:supportsRtl="true" is enabled in AndroidManifest.xml.
It happens when you use a RelativeLayout that contains items positioned with android:layout_centerVertical="true" or android:layout_centerInParent="true".
You can fix it in Java code like this:
View relativeLayout = layoutInflater.inflate(R.layout.my_relative_layout, parent, false);
// Fix RTL layout bug on Android 4.2 (for Arabic and Hebrew mode)
if (Build.VERSION.SDK_INT == 17 &&
getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
// Force a left-to-right layout
relativeLayout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
}
let me tell you correct answer, look your RelativeLayout(id:imageLayout),it's width is wrap_content, and your ProgressBar(id:progressbar) add an attribute android:layout_centerInParent="true".It means parent not limit witdh,and child also want to center,so parent will be stretched.

AutoResizeTextView does not resize after other Views are hidden (View.GONE)

Context:
I have two AutoResizeTextViews inside a LinearLayout. I would like to have the first one about 1/3 of the size of the second one, and both as large as possible. Therefore I use layout_weight=1 and layout_weight=3 as can be seen in the XML code below.
Problem:
When I hide other TextViews in the View of the Fragment (stored as mView), using:
textView7.setVisibility(View.GONE);
(..many more to GONE..)
more space gets available for the LinearLayout, and so I expect the AutoResizeTextViews to grow. However the two AutoResizeTextViews do not grow, and seem to keep their canvas size. They are moved to align to the new 1/3 ratio of the LinearLayout, so there really is space inside the LinearLayout.
When the Activity and the View is restarted upon device reorientation (I do not retain the Fragment) they DO change as expected, apparently the canvas is redrawn correctly then. How can I make the AutoResizeTextView to be redrawn correctly without have to turn the device?
Already tried:
mView.forceLayout();
mView.refreshDrawableState();
mView.requestLayout();
mView.invalidate();
linearLayoutAutoFit.invalidate();
tvTimer.invalidate();
tvTimer.setTextsize(999);
is all not working, the Text is not adjusted to the new size.
XML code:
<LinearLayout
android:id="#+id/linearLayoutAutoFit"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/viewline2"
android:layout_below="#id/progressBar3"
android:layout_alignParentLeft="true"
>
<AutoResizeTextView
android:layout_weight="3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="#string/Ready"
android:id="#+id/textViewAction"
android:textSize="999sp"
android:textColor="#ADFF2F"
android:singleLine="true" />
<AutoResizeTextView
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="#+id/tvTimer"
android:textColor="#fff"
android:text="#string/init_time"
android:textSize="999sp"
android:visibility="visible"
android:singleLine="true" />
</LinearLayout>
instead :
android:layout_height="wrap_content"
type :
android:layout_height="0dp"
Although the answer by Kastriot was very close, and also part of the solution, I found the solution today by testing the values inside the AutoResizableTextView class with Log outputs. The mistake I made was that I also had
android:layout_width="wrap_content"
Because of that, upon layout change, the width of the AutoResizableTextView was not adjusted! As a consequence, the text could not grow in size. Therefore the setting for the width should be:
android:layout_width="fill_parent"
such that the width of the AutoResizableTextView is large enough to fit a larger text.

Background of TextView with multiple lines not wrapping correctly

Background:
I've got a layout that consists of 6 items layed out as a grid (2x3). All items are as wide as half the screen (minus a little margin on each side). Each item is a RelativeLayout that contains an ImageView (the background) and a TextView (the label). The label is set to wrap the text, and it's allowed to grow almost as wide as the image it sits on top of. After that it will break into two lines.
Problem:
Everything looks good as long as the text fits on a single line (see top element in picture). The background wraps the text nicely. However, when the text is displayed on two lines the background gets too wide (see bottom item in picture). It fills up the maximum allowed width even though the text on the first line doesn't take up that much space. Is there a way to make the background wrap the text in the same way as it does when only one line is used?
Picture:
Layout XML:
<ImageView
android:id="#+id/item_image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="centerCrop" />
<!-- some stuff I had to remove... -->
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:paddingBottom="11.33333dp">
<!-- some other stuff I had to remove... -->
<!-- the gray background color is set to the TextView below programmatically together with the text itself. -->
<TextView
android:id="#+id/item_text_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5.33333dp"
android:paddingLeft="7.33333dp"
android:paddingRight="20dp"
android:paddingTop="1dp"
android:paddingBottom="5.33333dp"
android:layout_alignParentRight="true"
android:gravity="right" />
</RelativeLayout>
</RelativeLayout>
One of the possibility of such problem is textSize.
It depends on how you are setting and which measuring unit you are using to set textSize of your TextView.
dp,sp,pt and in may cause to create such problems.
So try to go with mm or px specifically.
And as per my testing px will give you the best result.
EDITED :
Add following attribute to your TextView in layout file.
android:gravity="right|start"
Instead of :
android:gravity="right"
Thanks.

Android: How to use an xml string value to determine layout orientation

I have a simple linear layout that I would like to change based on the screen size of the device. What I am trying to do is something like
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="#string/cover_orientation"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
I have created different dimen.xml files under values and values-xlarge so that the cover_orientation variable will take on a different value (either 'vertical' or 'horizontal') based on the screen size.
string name="cover_orientation">"vertical"
But this doesn't work. I have found a temporary work around that involves checking the screen size and changing the orientation manually:
if(getResources().getString(R.string.screen_size) == "xlarge"){
((LinearLayout)convertView).setOrientation(1);
}
but it seems like you should be able to do it the first way (much more elegant/less code).
I considered just having a different layout for each screen size, but the layout is actually quite big and this is the only change I need for the different screen sizes. So it didn't make much sense to me to duplicate the entire layout.
Thanks!
A nice way to do this is to add
android:orientation="#integer/cover_orientation"
on your LinearLayout and defining it like below.
in values/consts.xml:
<resources>
<integer name="orientation_horizontal">0</integer>
<integer name="orientation_vertical">1</integer>
</resources>
in values/something.xml:
<resources>
<integer name="cover_orientation">#integer/orientation_vertical</integer>
</resources>
in values-land/something.xml:
<resources>
<integer name="cover_orientation">#integer/orientation_horizontal</integer>
</resources>
This way you avoid hardcoding zeros and ones in your orientation variable definitions across the app.
I eventually found a solution to the problem by looking around the android docs. What I originally had was a LinearLayout, that contained an image an text inside of it (there was actually a lot more content inside of it but I'll keep it simple for this example), that looked something like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView android:id="#+id/cover"
android:layout_width="#dimen/cover_width"
android:layout_height="#dimen/cover_height"/>
<TextView android:id="#+id/title"
android:gravity="top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="#dimen/title_font_size"
android:scrollHorizontally="true"
android:maxLines="1"
android:ellipsize="end" />
</LinearLayout>
What I wanted was to be able to dynamically change whether the text was beside the image or below the image, based on the device screen size. In other words i wanted to dynamically change the android:orientation dynamically. My first thought, which I posted in my question, was to have a string variable declared in the res/values/dimen.xml as
<string name="orientation">horizontal</string>
and another string variable declared in res/values-large/dimen.xml as
<string name="orientation">vertical</string>
Then when I was setting the orientation in the LinearLayout I thought I could use
android:orientation="#string/orientation"
But this didn't work. What I ended up doing was splitting the layout up. I originally had reservations about having two separate layouts because I thought I would have a lot of duplicated code for one simple change. That was before I learned about include and merge. First I created a common layout file that was the image and text in res/layout/content.xml that looked like:
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<ImageView android:id="#+id/cover"
android:layout_width="#dimen/cover_width"
android:layout_height="#dimen/cover_height"/>
<TextView android:id="#+id/title"
android:gravity="top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="#dimen/title_font_size"
android:scrollHorizontally="true"
android:maxLines="1"
android:ellipsize="end" />
</merge>
(Sidenote: I was originally confused at what the merge tag did. It is not merging what is inside the merge tag (in this example the image and the text) it is basically saying whatever parent file includes this file, merge the contents in between the tags into the parent file)
Then I created two separate files for just the LinearLayout that included the image and description xml file. One in res/layout/container.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/library_item_container"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<include layout="#layout/content"/>
</LinearLayout>
and one in res/layout-large/container.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/library_item_container"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<include layout="#layout/library_item_contents"/>
</LinearLayout>
Notice the only difference between the two container.xml files is that the orientation has changed from vertical to horizontal. Now there is minimal code that is repeated and problem is solved!
#odiggity, thank you for posting this question. I was trying the same. Application crashed upon starting.
I would assume that it's a runtime typing issue. In other words, there are only two legal values for the orientation attribute, which is not reflected by the string "type". What the framework would probably have to do is introduce another specialized resource type, similar to dimen or boolean.
I feel there is an answer to your question which addresses more cases than your own answer above. One can use style inheritance to define all attributes except orientation in an orientation-independent parent style and then add only the orientation in a small orientation-dependent style definition with that as a parent.
This way, one can avoid duplication even in complex cases.
I suggest you do some reading: http://developer.android.com/guide/practices/screens_support.html

Categories

Resources