How to make textview "grow" from right? - android

I'd like to create a message-like UI. I'm creating a list view with two types of rows: left and right.
Each row contains one TextView. The left one is used to display the message from the sender, while the right one is used to display the message from the current user.
What I would like to do is to set the TextView in the right row to occupy certain percentage of the screen, have text aligned to the left but to grow dynamically with the content.
To clarify, here is an image of what I would like to achieve: http://dl.dropbox.com/u/2482095/wanted.png
Blue rows are "left" rows, black rows are "right" rows.
To achieve this, I have used various combinations of LinearLayout and RelativeLayout with an empty view placed to the left, and desired textView placed to the right. What I get I something like this, which is not what I want: http://dl.dropbox.com/u/2482095/notWanted1.png (text always starting at the exact point)
I have also managed to set gravity:right, which aligns text to the right, which is also not what I wanted.
Is there any way to make TextView grow with its content?
[edit] My xml file looks something like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp">
<View android:id="#+id/emptyView"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView android:id="#+id/messageBody"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

You should set layout_width="wrap_content" on your TextView, and layout_weight="1" on your empty view. That way, the TextView should just be as wide as needed, and the extra space will be taken by your empty view.

Basically what you want is the text to be right-aligned if it fits in one line, and left-aligned otherwise.
To measure the width of the Text use the Paint.measureText() method. So you might use something like this for your view:
Paint paint = new Paint(view.getPaint());
LayoutParams params = view.getLayoutParams();
int availableWidth = params.width - view.getPaddingLeft() - view.getPaddingRight();
int textWidth = (int) Math.ceil(paint.measureText(view.getText().toString()));
if(textWidth <= availableWidth) {
view.setGravity(Gravity.RIGHT);
}
else {
view.setGravity(Gravity.LEFT);
}

Yes, have your view (any view) wrap_content. This will allow the view to grow as large as its parent will allow. If your parent only allows a certain amount of space for your view to take, the child will never grow larger. Not, a parent is also limited by its parent and so on.

Related

how to limit textView's width according to left width

I have a layout (can be relative, linear or constraint)
with TextView aligned to parent left and then ImageView (fix width) aligned that start right to the textView.
I want the image to be rendered first and only then to render the text view.
Meaning I want the text view to be truncated according to the left space after the image was rendered.
<RelativeLayout
android:id="#+id/account_name_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginBottom="#dimen/account_menu_account_name_layout_bottom_margin">
<TextView
android:id="#+id/account_name"
style="#style/AccountDataAccountName"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:lines="1"
android:ellipsize="end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
tools:text="emailisverylongaswellwewantittogettruncated#gmail.longdomain.com"/>
<ImageView
android:id="#+id/account_name_chevron"
android:layout_width="#dimen/account_menu_chevron_size"
android:minWidth="#dimen/account_menu_chevron_size"
android:layout_height="#dimen/account_menu_chevron_size"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/account_name"
android:layout_marginTop="#dimen/account_menu_chevron_top_margin"
android:layout_marginLeft="#dimen/account_menu_chevron_left_margin"/>
</RelativeLayout>
I have tried few options:
1) telling the text to be left to the image view
2) putting weight on the text view - made gap between the two elements.
3) setting minWidth to the image view - didn't help just made the imageView scale smaller.
Any idea how to render the image first and how to limit textView's width according to left width?
You can force the width on the imageView. That will prevent the textview from pushing it off the space. If you are saying you did this, please post the resulting image as that wouldn't make any sense.
Your above example has no constraints to each other, no enforcement to not overlay or push off. You need some constraints, such as "toTheLeftOf" or "Weight" or LinearLayout to enforce it as Weight only works in LinearLayout.
The easiest way is to just give the imageView a hard coded DP width and height, then set the text to 0 width with a weight of 1 inside a Linear Layout.
You can also use percentages if you want, use a LinearLayout then put a weight sum of like 100 for example (representing 100%). Then assign your image whatever percentage it needs like layout_weight=30 and give the textview 70.
Any of these options will work fine for you. If you try it, and it does not, then post your tried code as it will work unless you are doing something goofy that is not visible in your current example. As I do this all the time, every time you make a row, you typically have an image on the left fixed and text on the right to grow.

How can I add padding to a View?

I am trying to make a View as a divider on my application to separate two elements (two Buttons, two TextViews or whatever) and I would like to have a padding on the left and on the right of that View (to move the background some space on the left and on the right).
It allows you to set a padding but the View still continues occupying the full width screen. Here is the code I have:
<View
android:layout_width="wrap_content"
android:layout_height="0.5dp"
android:background="#FFFFFF"
android:paddingLeft="10dp"
android:paddingRight="10dp"/>
How can I set a space on the left and on the right of that View so the divider will be smaller than screen?
Thanks in advance!
use margins instead of padding
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
Finally I got it. As on Android documentation it says: Even though a view can define a padding, it does not provide any support for margins, I am not able to use marginLeft or marginRight properties.
If you try to set directly android:marginLeft="10dp" you will get the following error:
No resource identifier found for attribute 'marginLeft' in package 'android'
Nevertheless, you can use android:layout_marginLeft="10dp" and android:layout_marginRight="10dp" to get the desired result.
The final View xml will be like this:
<View
android:layout_width="wrap_content"
android:layout_height="0.5dp"
android:background="#FFFFFF"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"/>
Padding takes care of the inner space. Therefore you would use padding to increase the space between the outline of the view and the elements inside it, whether they are buttons, textviews etc.
Margin takes care of the outer space. You would use this to increase the space between the outline of the view and the element which contains it. Hence what you need. To implement this in a view use the following:
private void setMargins (View view, int left, int top, int right, int bottom) {
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
p.setMargins(left, top, right, bottom);
view.requestLayout();
}
}
Hope this helps :)

Aligned Views: Change position of Anchor and update aligned View's position

I'm generating my Views programatically, so there's no XML. But as it is easier to show my problem, I will give the structure in XML-like notation
<RelativeLayout
android:id="#+id/mainLayout">
<LinearLayout
android:id="#+id/left"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:maxWidth="300dp"
android:maxLines="3"
android:text="Some long Text" />
</LinearLayout>
<ImageView
android:id="#+id/right"
android:layout_toRightOf="#id/left">
</RelativeLayout>
For this, the LinearLayout is positioned in the top left corner of the RelativeLayout. The ImageView is positioned right to it.
The TextView is very important. You see it's width is variable but to a maximum of 300dp. With this and maxLines this TextView has a maximum area by the size of 300dp x 3 lines. Most likely, the TextView won't be this large and by the wrap_content settings, TextView and LinearLayout will adapt to the text.
(I have to say, I overrid the TextView's onMeasure method, so the TextView is only as wide as the widest line.)
At the moment, everything is ok. The TextView and therefor LinearLayout enclose the text tightly, sitting at (0, 0). Next to it on the right sits the ImageView. Now comes the hard part I'm stuck at.
I want to align the LinearLayout within the before mentioned area, the TextView could maximally span. First thought was, I surround the LinearLayout with another RelativeLayout, by the maximum size and position the smaller LinearLayout within. But as the ImageView must have to be a direct child of mainLayout, I can't align it to the LinearLayout anymore.
My current approach is to override the LinearLayout's onLayout method:
#Override
protected void onLayout(boolean changed, int left, int top,
int right, int bottom){
super.onLayout(changed, this.getLeft(), this.getTop(),
this.getRight(), this.getBottom());
int translation;
int widthNeed = this.mLinLay.getMeasuredWidth();
switch(this.mLinLayAlignment)
{
case Left:
break;
case Center:
translation = (this.mLabWidth - widthNeed)/2;
this.setLeft(this.getLeft() + translation);
this.setRight(this.getRight() + translation);
// also tried: this.setTranslationX(translation);
break;
case Right:
translation = (this.mLabWidth - widthNeed);
this.setLeft(this.getLeft() + translation);
this.setRight(this.getRight() + translation);
// also tried: this.setTranslationX(translation);
break;
}
}
I only want to align the LinearLayout horizontally by now, so I only distinguish between 3 cases. The translation works pretty well, but the ImageView stays on its place, where it aligns to the initial position of the LinearLayout. I first tried LinearLayout.setTranslationX() but with the same effect. So I changed it, because the documentation on setTranslationX implicated, translation happens after layouting.
I think I just have to call the right method, so mainLayout is forced to layout the ImageView again, but I can't find it.
Also, are these the proper way and place to move the LinearLayout? As I need the final size of the TextView, it had to be measured, so this is the place I have to do it, I think.
EDIT
I have tried a little more. I got the LayoutParams from the LinearLayout, increased the left and decreased the right Margin by the calculated translation and set the LayoutParams again. Well, the ImageView still stays in place, so no progress here. But after switching out and back in the app, I realised, the Margin changed every time layouting. Well, should have seen this coming.
But why isn't the same thing happening, using setLeft and setRight?
Maybe if you draw a picture of what you want it would help.
I would stay out of the onLayout method alltogether.
If you want to move View or Layout around, then use layout params
RelativeLayout.LayoutParams params = linearLayout.getLayoutParams();
params.setMargins(left, top, right, bottom);
linearLayout.setLayoutParams(params);

TextView in the right side of parent

So I'm trying to put a textview to the left side of an image that fills the parent. Any ideas how to do it in XML? are there any ways to put the textview with witdh 200dp and height 300dp but in the right corner of the parent?
TY
Here's my code for the imageview to the left:
<TextView
android:id="#+id/display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:width="200dp"
android:height="300dp"
android:gravity="left"
android:background="#00ffffff"
/>
Note that I am new with this
Use the following attribute in your text view:
android:layout_toLeftOf="#id/your_image_view_id"
Just make sure your ImageView is declared in your xml before the TextView and you give it an id (as an example, android:id="#+id/your_image_view_id").
If I understand this correctly, you are wanting to "Overlay" the text views on top of the Image?
I.E. The image occupies the entire parent view and the text views align with the top and left edges of the image..
If that is the case you probably want something like:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/superawesomeimage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/photoofmyholiday" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#id/superawesomeimage"
android:layout_alignRight="#id/superawesomeimage"/>
</RelativeLayout>
This should produce a textView along (the top by default) of the image, matching the image width of the image container (to make the image fully occupy the imageview you will need to specify a scale I think (fitXY probably).
I might be a bit off with the keywords/syntax here.. I was just typing it off the top of my head, but you get the general idea.
The important things to note are the order of the TextView/ImageView (it determines who is on top of whom) and the TextView layout alignment. With relative layouts you can position relative to other views.. so setting align left and align right to the image will make the left and right edges of the text view line up with the left and right edges of the image view. Hope that helps. Have fun!
I am not sure what you want to align where but if you want something aligned on the right you can use this in a RelativeLayout:
android:layout_alignParentRight="true"

How to create two views in Android that use 50% height each, unless one is smaller?

Imagine a full Android device screen, I want it split in to two sections:
The upper half has text in it, which may be larger than the space available (or not) and so the text will scroll (i.e. TextView inside a ScrollView)
The lower half contains a MapView control.
Looking specifically at some scenarios:
If the text is small, I want the map to take up more space, i.e. more than 50%. So perhaps 20% text, 80% map.
If the text is larger, it only takes up a MAXIMUM of 50% of the screen space, and then scrolls. So 50% map, 50% text.
At the moment I've assigned weights to the two parts, and that isn't too bad, but if the text is small, the map doesn't expand to take the space, and the layout has a wasted gap that the map could usefully use.
I've tried loads of combinations but can't see how to make this happen. It seems to be a common experience for me that I know what I want, but can't see how to get the available views to deliver it. I'm hoping there's a nice easy way to do this.
Please feel free to make me look like a fool and point out the obvious attribute I've missed :-)
======================================================================
As far as I can see there's no way to do this just in declarative XML and it needs doing in the code. I set the text section height to wrap_content, weight to 0 (no resizing), and have the map set to weight=1 (i.e. take up the remaining space). I then check if the text section (in a ScrollView) is taking up too much space and if so, shrink it back. This code would need changing to support a different layout orientation.
private void fixLayoutProportions()
{
float maxPercentageOfScreenForText = 50/100;
LinearLayout container = (LinearLayout)findViewById(R.id.container);
ScrollView eventText = (ScrollView)findViewById(R.id.text_scroller);
int heightAvailable = container.getHeight();
int scrollerHeight = eventText.getHeight();
if ( scrollerHeight>(heightAvailable*maxPercentageOfScreenForText) ) // Text section using too much space
{
eventText.getLayoutParams().height = (int)(heightAvailable*maxPercentageOfScreenForText) ;
eventText.invalidate();
}
}
You can do it by putting everything into LinearLayout and changing following parameters:
the sum of weights for LienarLayout
weights for children
Did you try to measure your screen hight at run time:
Display display = ((WindowManager)
getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int width = display.getHeight();
Then, set your top view max_height to width*0.5 and min_height to width*0.2. Your top view has to be control (like TextView) that has min_height and max_height properties. Also, set layout_weight to 0 or leave it empty.
On your bottom view set layout weight to 1.
The easiest way to do 50/50 is in XML is using LinearLayout weights. Basically put the two views into a single LinearLayout set the android:layout_weight on both child views to the same value, like setting both to .5, 1, or 42. You then set the layout_width to 0px or fill_parent/match_parent.
The smaller part gets more complicated. Luckily, you can turn off weighing in Java. One way is to wait until the windows get drawn (if they are pre-populated) and measure them. This can be done on I think it was called onWindowFocusChanged
I haven't tested this, but I'd try setting your ScrollView to have android:layout_weight="1" and your MapView to have android:layout_weight="0" and a android:minHeight="240dp". The hope is that minHeight will have precedence over layout_weight.
i think you have to set mapviews height as fill parent and set textviews height as wrap contetn and than for scrolling you have toset vertical scrool true for text view and as you nedded not more than 50% space textview you can set maxheight property of textview.
I am sorry if you find this trivial.
But I am suggesting it in case it did not strike you.
How about using relative layout and keeping the textview always on top of the map.
Make the gravity of the textview top, its width match_parent, its height wrap_content and its weight 1(same as that of thee map). That way your textview will change according to the size of the text, while not going above 50% because of the weight. As for the map, the user can pull the map down to see the hidden part under textview. It'll be as if there is no map under the textview(you know, unless you want to make the textview background transparent which i think would look cool :) ). I do not know about the map view. But I am assuming it'll be something like google maps on iphone, like you can vary size using multi-touch and scroll using single.
OK as I see its something like u are reserving at max half of ur screen to the TextView and if its more it has to scroll. I have a solution but for that you will have to fix the max no.l of lines for TextView, calculating which can be a pain :P but have a solution never the less.
main.xml file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:maxLines="5"
android:id="#+id/tv1"
android:text="wsdvsv sjdgv jsdvn ksdjbn skjdb ksdnbk snbk snbjksn fkbj sfkbjn dfkjbndkjfbn kdjfnb kjdfnbkjdnfbk ndf bjkndf bndfjbn dfkbn jdfnbjdfnbjdfn bjdf nbkjdnf bkjdfnb kjdnfbkjdfn bkjndfbjndfjbndkjfbn dkfjbn kdjfnb kjdfnbkjdfnbjkd nfkjbndf"
/>
<TextView
android:layout_width="fill_parent"
android:layout_below="#id/tv1"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:maxLines="5"
android:text="Does it work ???"
/>
</RelativeLayout>
Java file:
package com.android;
import android.app.Activity;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.widget.TextView;
public class TestActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView tv = (TextView) findViewById(R.id.tv1);
tv.setMovementMethod(new ScrollingMovementMethod());
}
}
If the text is say only in 2 lines "Does it work?" will shift up automatically. But the only problem i see here is the max lines to 5 is you can an max value for u i guess this might work well :)
BR,
J
P.S. I haven't answered many questions before so i m not sure how to attach files :(

Categories

Resources