Have TextView scale its font size to fill parent? - android

Is there a way to have a TextView pick a font size such that it fills whatever space it has available? For example:
<LinearLayout
layout_width="fill_parent"
layout_height="50dip" >
<TextView
layout_width="fill_parent"
layout_height="fill_parent"
textSize="scale?" />
</LinearLayout>
Thanks

No, there is not built in font scaling in a TextView. You could overload the onDraw() method in a child of TextView, but TextView does not support scaling the text automatically.
Take a look at this other question.

Just to update, from API 26 (Android 8.0) TextViews has an attribute to scale text on horizontal and vertical axes
<?xml version="1.0" encoding="utf-8"?>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:autoSizeTextType="uniform" />
Check it at Autosizing TextViews

As in the answer Nick Campion quoted, I used a loop and a static layout to iterate to the correct size. My requirements were to fit the width and use no more than one line (no ellipses):
int i = 0;
while(i < 2) {
layout = new StaticLayout(text, textPaint, w, Alignment.ALIGN_NORMAL, 1, 0, true);
i = layout.getLineCount();
textSize += 2;
textPaint.setTextSize(textSize);
}
textPaint.setTextSize(textSize*0.95f);

Related

How to explain this weird behaviour when programmatically setting margins to a view inside RelativeLayout?

I have a RelativeLayout inside a fragment that one of three tabs in a TabView. See this Screenshot - big pink square is my RelativeLayout:
screenshot
The view that is inside it is the little blue square in the bottom right corner. Since the RelativeLayout is 300x300dp and the little square is 8x8dp, if I set its top and left margin to 292dp it ends up in that corner.
Now I want to change its position programmatically, but when I do it, my values keep getting divided by two. So if I change the margins from 292 to 292 it ends up in the center of the RelativeLayout, but if I set each to 292*2, it ends up back in the corner.
Maybe there is someone who knows what is happening here?
This is my layout file:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:width="40dp"
android:height="40dp"
android:background="#color/colorAccent"
android:text="Test!" />
<RelativeLayout
android:layout_width="300dp"
android:layout_height="300dp"
android:background="#color/colorAccent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<View
android:id="#+id/position_dot"
android:layout_width="8dp"
android:layout_height="8dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:background="#color/colorPrimary"
android:layout_marginLeft="292dp"
android:layout_marginTop="292dp"/>
</RelativeLayout>
</android.support.constraint.ConstraintLayout>
</layout>
and this is the method I use to update the margins:
fun moveDotToCurrentPosition() {
var params = positionDot.layoutParams as RelativeLayout.LayoutParams
params.topMargin = 292
params.leftMargin = 292
positionDot.layoutParams = params
}
I tried to keep the code short and limited to what's relevant, if something important is missing please let me know and I put it in.
I'm writing this one in Kotlin, but Java answers will be helpful too.
Thank you.
Almost all Java-code dimension values that are just raw int or float use px units, not dp. It is very likely that you are executing your code on an hdpi device. If so, your screen density means that 1dp == 2px, and this would explain why everything seems to be "divided by 2".
You can find your current screen density with code like this:
float density = [context].getResources().getDisplayMetrics().density;
And you can then multiply any dp values by this density to get the px values.
Alternatively, if you're working with dimensions that you've stored as <dimen> resources, you can just call:
int dimen = [context].getResources().getDimensionPixelSize(R.dimen.my_dimen);
The values you are using to update your margins are in px size
params.topMargin = 292
params.leftMargin = 292
If you want to change them to 292dp you should load a dimen resource or multiply the value for displayMetric density
You can use the anko dip function
fun Context.dip(value: Int): Int = (value * resources.displayMetrics.density).toInt()
Your code will look like this:
params.topMargin = dip(292)
params.leftMargin = dip(292)
Maybe this can fix your issue.

How to adjust view layout based on text size

I have a view that I want to layout in either a large format or compact format depending on the length of text in a textview like so:
What is the best way to achieve this?
I am thinking I will need to measure the length of the text and the controls and get the available space to see if they would fit on one line. If they will then use a compact layout otherwise use the large layout.
Is this the right approach or is there a way to achieve this with a single layout?
The layout you require is something called FlowLayout. But android SDK doesn't have such a layout support currently. There are nice 3rd party libraries available & one of them is FlowLayout.
Gradle:
compile 'com.wefika:flowlayout:0.4.1'
In your layout :
<com.wefika.flowlayout.FlowLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="start|top">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lorem ipsum" />
</com.wefika.flowlayout.FlowLayout>
Put both in a LinearLayout and set its orientation programically in java file like this
LinearLayout layout = /* ... */;
layout.setOrientation(LinearLayout.VERTICAL);
Set Horizonatal if you want compact and set vertical if you want large one.
and put condition based on the width you get from below code
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
You can try to make user set texts for all your textViews and after use something like this:
RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
if(layout.getWidth()/2<Title.getWidth()){
p.addRule(RelativeLayout.BELOW, R.id.Title);
controls.setLayoutParams(p);
}else{
p.addRule(RelativeLayout.RIGHT_OF, R.id.Title);
controls.setLayoutParams(p);
}
It is called a FlowLayout. Google it for multiple libraries that support it.

How to set a textView width dynamically larger than the width of the screen after animation?

I have a text view with a height which wraps content and a width that matches parent. So that the textView width == the screen Width.
But at one point I want the text to rotate 90 degrees.
Now I want to be able to change the views width so that it is the devices height instead of width.
This would cause that the width would expand.
(Basically like when one does orientation changes, but I can´t just have an orientation change for only one textview so I have to rotate it.)
My problem: I can´t set the textViews width larger than the device width.
Even when I am already done with the animation.
So is it possible to make the textView width larger than the device width?
and if not can anyone please suggest how I could solve my problem because I really need to change the orientation of the textView...
EDIT----EDIT
Is there a way to create a landscape text view and put it in a portait activity? That would completly solve my problems of the last week...
EDIT
My fragment:
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/f"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/t"
/>
</RelativeLayout>
I tried different things like
fragment.setRotation(90);
LayoutParams params = fragment.getLayoutParams();
params.height = text.getHeight();
params.width = deviceHeight;
fragment.setLayoutParams(params);
LayoutParams params1 = text.getLayoutParams();
params1.height = text.getHeight();
params1.width = deviceHeight;
text.setLayoutParams(params1);
EDIT________EDIT
Or has anyone ever written something like a verticalTExtView Class?
You can set the attributes of TextView as android:singleLine="true" and android:layout_width="wrap_content" and android:layout_height="wrap_content" // incase if you do not want the height to be increashed so singleLine is making the text to go out of screen width then you will need ScrollView for such behavior.
Hope this helps.

Android textView size is bigger than dynamically created one

I got some issue with dynamically created TextViews. To be more specific:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Some text"
android:textColor="#color/black"
android:textSize="30px" />
appears much larger than:
TextView prName = new TextView(this);
prName.setTextColor(getResources().getColor(R.color.black));
prName.setText("Some text");
prName.setTextSize(TypedValue.COMPLEX_UNIT_PX, 30);
How to made them equal? Thanks beforehand
For text you should use scale points (SP) instead of pixel.
For xml:
android:textSize="30sp"
For code:
prName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 30);
Set height and width as wrap_content for your textview.
LinearLayout.LayoutParams Params1 = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
prName.setLayoutParams(Params1);
Make sure when you setTextSize for any type of view, you should set it in scalable points (sp) and not in pixels (px) like this:
In xml:
android:textSize="18sp"
In code:
prName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
Using scalable points will let your TextView text size be equal on all devices, while using pixels will let your TextView text size be unequal on devices with different resolutions.
use setTextSize(int unit, float size)
TypedValue.COMPLEX_UNIT_PX //Pixels
TypedValue.COMPLEX_UNIT_SP //Scaled Pixels
TypedValue.COMPLEX_UNIT_DIP //Device Independent Pixels
In here just set
prName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
Remove this line:
prName.setTextSize(TypedValue.COMPLEX_UNIT_PX, 30);
... or use this instead:
prName.setTextSize(30);

How to create a view that is bigger than the screen?

Is it possible to create a view that is bigger than the screen?
I need a view that has a bigger width then the screen of the device. I use this view in a rotation animation. During the rotation the parts that were not on the screen before animating the view will become visible.
Is there a way to achieve this effect with the android framework?
Update
I tried to set my parent layout much bigger then the screen and it is working. This will make somethings a little bit uncomfortable but it could work. The next problem now is that my layout still starts at the left side of the screen. I can't think of a method to make the layout to expand itself to the left and the right of the screen.
Ok I got an answer. It is not very nice because it uses a deprecated View class but it works at least on my current testing screen resolution other resolutions are tested tomorrow.
I wrapped the view that I wanted to expand beyond the screen in an absolute layout like this:
<AbsoluteLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true">
<ImageView
android:id="#+id/content"
android:layout_width="600dip"
android:layout_height="420dip"
android:scaleType="centerCrop"
android:layout_x="-200dip"
android:layout_y="60dip"
android:src="#color/testcolor" />
</AbsoluteLayout>
The -200 x coordinate makes the view stick 200dip out of the left side of the screen. If I'm animating the view those parts that are outside the screen will gradually become visible.
E.g. setting negative bottom margin together with setting extra large layout_height (large enough for you) solved the similar issue as for me.
Works fine at least using API 11+ animations/rotations.
Could look like:
android:layout_marginBottom="-1000dp"
android:layout_height="1000dp"
In case anyone still comes up on this page. The key is your root layout, it will only work with a FrameLayout (or the deprecated absolutelayout). Then you have two options to make your child view bigger.
through xml, this is quick and easy but you don't know the actual screen width & height in advance so your off with setting a ridiculously high value for layout_width & layout_height to cover all screens.
Calculate the screen size programatically and make the view's width/height proportional bigger to this..
Also be aware that your bigger view still starts in the top left corner of the screen so to account this you will have to give a negative top & left margin that's half of what you are adding to the view's width/height
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) viewToMakeBigger.getLayoutParams();
int marginLeft = (int) (viewToMakeBigger.getWidth()*0.1);
int marginTop = (int) (viewToMakeBigger.getHeight()*0.1);
params.width = (int) (viewToMakeBigger.getWidth()*1.2);
params.height = (int) (viewToMakeBigger.getHeight()*1.2);
params.leftMargin = -marginLeft;
params.topMargin = -marginTop;
viewToMakeBigger.setLayoutParams(params);
HorizontalScrollView:
http://developer.android.com/reference/android/widget/HorizontalScrollView.html
Layout container for a view hierarchy that can be scrolled by the user, allowing it to be larger than the physical display.
The simple axml below creates an ImageView that is 400dp wider than the screen (even though the layout_width is set to equal the parent's width) using a negative left and right margin of 200dp.
The ImageView is situated 250dp above the top of the screen using a negative top margin, with 450dp of 700dp vertical pixels visible on the screen.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:background="#FFFF0000"
android:layout_height="700dp"
android:layout_marginLeft="-200dp"
android:layout_marginRight="-200dp"
android:layout_marginTop="-250dp"
android:layout_width="match_parent" />
</RelativeLayout>
You can override the views in the onMeasure method. This will set your View dimensions to 1000x1000 px.
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(1000, 1000);
}
Is it possible to create a view that is bigger than the screen?
Why not, you can define the layout_width and layout_height in px(or dip) as you want:
android:layout_width="10000px"
android:layout_height="20000px"
You need to change the size of the window, by getWindow().setLayout. This will increase the size for your window. Since the root layout can be as big as its parent you can then increase the size of the view you want to be bigger than the screen size. It works for me let me know
You can use ViewSwitcher to handle that. Used with Animation and a OnGestureListener looks pretty good.
You can do it programmatically:
FrameLayout.LayoutParams rootViewParams = (FrameLayout.LayoutParams) rootView.getLayoutParams();
rootViewParams.height=displayMetrics.heightPixels+(int)dpToPixels(60);
rootViewParams.width=displayMetrics.widthPixels+(int)dpToPixels(60);
rootView.setLayoutParams(rootViewParams);
rootView.setX(rootView.getX() - dpToPixels(30));
rootView.setY(rootView.getY() - dpToPixels(30));
MUST BE ONLY IN
"public void onWindowFocusChanged(boolean hasFocus)" method.
and
rootView = (RelativeLayout) findViewById(R.id.rootLayout);
Inside "protected void onCreate(Bundle savedInstanceState)" method.
Where yout .xml file is like this:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rootLayout"
tools:context="com.example.Activity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_centerHorizontal="true"
android:layout_margin="30dp"
android:layout_centerVertical="true"
android:layout_height="match_parent">
// Bla bla bla
</RelativeLayout>
and:
public float dpToPixels(float dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
}

Categories

Resources