How to set the layout_weight of a TextView in code? - android

I have looked around, but most of them don't make any sense. Some have a third parameter that does not exists in the Android docs, at least anymore. Anybody have any idea how to accomplish this? I have this so far:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.day_view_item, parent, false);
}
((TextView)convertView.findViewById(R.id.day_hour_side)).setText(array[position]);
if(count == 1) {
LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.day_event_layout);
TextView create = new TextView(parent.getContext());
create.setLayoutParams(new LayoutParams(0, 30));
create.setBackgroundColor(Color.BLUE);
create.setText("Test");
layout.addView(create);
count = count -1;
}
return convertView;
}
I am trying to add it to a LinearLayout in a ListView, hence the method you see in the code. One problem is that the TextView is not showing up when I run it. So I was thinking I need the layout_weight. Though, I am confused about one thing. What values are the width and height parameters of the LayoutParams constructor (dp or px)? I will also add the xml of where I am trying to add it at incase that is helpful:
<?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="horizontal" >
<TextView
android:id="#+id/day_hour_side"
android:layout_width="wrap_content"
android:layout_height="62dp"
android:text="12AM"
android:background="#bebebe"
android:layout_weight="0"
android:textSize="10dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"/>
<LinearLayout
android:id="#+id/day_event_layout"
android:layout_width="0dp"
android:layout_height="62dp"
android:layout_weight="1"
android:paddingTop="1dp"
android:paddingBottom="1dp"
android:orientation="horizontal" ></LinearLayout>

Firstly, the LayoutParams constructors use pixels (according to the documentation).
To set the layout_weight programmatically, you need to use LinearLayout.LayoutParams. ViewGroup.LayoutParams does not have a third argument, as you pointer out, but the former does.
Try this:
create.setLayoutParams(new LinearLayout.LayoutParams(0, 30, 1.0f));
ViewGroup.LayoutParams is a set of layout parameters for any View within any kind of layout (since these layouts are all ViewGroups). When you have a specific layout, for example a LinearLayout, you can use LinearLayout.LayoutParams to get access to things specific to that type of layout. In this case, the layout_weight is particular to LinearLayouts, therefore you must be using the LinearLayout.LayoutParams to access this weight parameter.
You should also remove the layout_weight="0" from the TextView in your XML. If this still doesn't fix it, give your LinearLayout a background color and see if it's even visible at all, then edit your OP with your findings and any changed/new code.

Related

Custom ListView set Background Drawable in XML doesnt work

I'm getting frustrated about this:
When I define a custom ListView Layout,
Android Studio doesn't keep the background drawable I set in there.
Tried many things, and setting background programmatically doesn't work
since it's ignoring the layout_width which must be set to "wrap_content".
Actual style of background
Result without coding
If anyone could help me, I'd be very grateful !:)
EDIT:
I'm creating a Messenger and I want to display messages in a similar way to WhatsApp, where messages are shown in a listView. Depending on message is sent or received, items should be aligned ParentStart or ParentEnd.
But more importantly, if a message only contains a few chars, I don't want the ListItem Background to fill the entire screen, so it should be set dynamically.
I thought I could achieve this through simply setting wrap content in the parent layout file.
Files look like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentEnd="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp"
tools:background="#drawable/background_message_sent">
//Here are TextViews
</LinearLayout>
</RelativeLayout>
Here is my ListViewAdapter, where I set background
(#drawable/background_message_sent/received) programmatically.
However, this covers the entire width of ListView, regardless of message length.
#Override
public View getView(int pos, View convertView, ViewGroup parent) {
int currentUserID = 1;
int senderID = messagesArrayList.get(pos).getSenderID();
if (senderID == currentUserID){
View v = View.inflate(context, R.layout.layout_chat_message_sent, null);
v.setBackgroundResource(R.drawable.background_message_sent);
TextView tvMessageText = v.findViewById(R.id.tvMessageText);
TextView tvTimeStamp = v.findViewById(R.id.tvTimeStamp);
tvMessageText.setText(messagesArrayList.get(pos).getMessageText());
tvTimeStamp.setText(messagesArrayList.get(pos).getTimeStamp());
return v;
}
else {
View v = View.inflate(context, R.layout.layout_chat_message_received, null);
v.setBackgroundResource(R.drawable.background_message_received);
TextView tvMessageText = v.findViewById(R.id.tvMessageText);
TextView tvTimeStamp = v.findViewById(R.id.tvTimeStamp);
tvMessageText.setText(messagesArrayList.get(pos).getMessageText());
tvTimeStamp.setText(messagesArrayList.get(pos).getTimeStamp());
return v;
}
}
Well, after trying, I got the solution if anyone comes to this point:
You have to set your background drawable directly for each TextView, not for Parent Layouts.
These two Lines finally solved everything ^^
android:maxEms="14"
android:background="#drawable/background_message_sent"
<TextView
android:id="#+id/tvMessageText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginEnd="0dp"
android:layout_marginTop="5dp"
android:layout_weight="0.22"
android:text="42456456456546"
android:textColor="#color/tentakelPrimary"
android:maxEms="14"
android:background="#drawable/background_message_sent"/>

Inflate a custom view from XML, then set her height and witdh programmatically

I'm loosing myself in an custom size View problem since a couple of days. After some long research, I finally decide to ask your help... please ! T_T
In my app, I created a custom View with the XML calendrieradmin_day.xml :
<?xml version="1.0" encoding="utf-8"?>
<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/CalendrierAdmin_Day_Event_TableRow"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<!-- <TextView
android:id="#+id/CalendrierAdmin_Day_Event_TextView_Name"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:gravity="center" />-->
</TableRow>
For now, it is a simple TableRow, but I'll need to add some other things in the future. (The commented TextView, for example).
I made three classes for using it : Row, EventRow and EmptyRow. Row is abstract and EventRow and EmptyRow inherit of Row. Also, Row inherit of TableRow.
I want to add several EventRow and EmptyRow in a TableLayout and I need to resize them dynamically.
In the constructor method of EmptyRow and EventRow, I call an init() method. Here the one of EventRow :
private void init(Context c, TableLayout root) {
root = (TableLayout)LayoutInflater.from(c).inflate(R.layout.calendrieradmin_day_event, root, true);
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) root.getLayoutParams();
lp.height = getHeightOfMinute() * getDuree();
lp.width = getTheWidth();
/*
Some other stuff
...
...
*/
this.setLayoutParams(lp);
root.addView(this);
setOnClickListener(this);
setOnLongClickListener(this);
}
Of course, it doesn't work as excepted. The EventRow is not showed.
root is my TableLayout I pass in the constructor. getHeightOfMinute() and getDuree() work correctly and give me the right sizes. I used to use the inflate() method like inflate(R.layout.calendrieradmin_day_event, null, false) and it worked fine, but Eclipse gave me a warning, telling me I shouldn't pass null as the RootView argument. Although everything worked fine, I begun to search another solution and this is where I gone so far...
I used the setMinimumHeight() and setMinimumWidth() method to rezise my EventRow and EmptyRow. It works, but I think there is a better way to do that. I tried A LOT of solutions but I messed up ! I think there is something I still not catched about the functioning of inflate() and/or LayoutParams.
Could you help me ? Thanks in advance !
Please tell me if you need more piece of Source code.
PS: Sorry for the bad english, I'm french.
I finally managed it, but a lot of things have been changed.
First, I drop the TableLayout and TableRow. Now it is simply some LinearLayout.
calendrieradmin_day.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/CalendrierAdmin_Day_Event_LinearLayout_Container"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:orientation="horizontal" >
<TextView
android:id="#+id/CalendrierAdmin_Day_Event_TextView_Name"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="left"
android:background="#drawable/background_event_full"
android:gravity="left" />
</LinearLayout>
And this is the init() method :
private void init(Context c, LinearLayout root) {
LinearLayout container = (LinearLayout) LayoutInflater.from(c).inflate(R.layout.calendrieradmin_day_event, root, false);
TextView name = (TextView) container.findViewById(R.id.CalendrierAdmin_Day_Event_TextView_Name);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0, duree);
container.setLayoutParams(lp);
name.setLayoutParams(lptv);
name.setText(e.getNom());
root.addView(container);
name.setOnClickListener(this);
name.setOnLongClickListener(this);
}
Pay attention to the LayoutParams lp (It's a LinearLayout.LayoutParams). duree is the duration of my event, in minutes.
My EventRow are intended to be in an another LinearLayout, llEvents. It contains all the events for one day, so 1440 minutes (60 x 24). As a result, the weightSum of llEvents is 1440.
I dropped the EmptyRow and the Row class to. I just add some empty LinearLayout to llEvents for the free time schedules, with there duration as weight.
It's REALLY important to presize a "0" height in the LayoutParams
Hope It will help someone ;-) !

Android ImageView size unexpectedly changing at runtime

In one of my activities, I have a table layout with cells that are added at runtime via a custom class. The layout for my cells is as follows:
<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+cell/style_2"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="5dp" >
<View
android:id="#+cell/divider"
android:layout_width="fill_parent"
android:layout_height="2dp"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="#FF000000" />
<ImageView
android:id="#+cell/image"
android:layout_width="fill_parent"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="#cell/divider"
android:layout_margin="5dp"
android:contentDescription="#string/row_thumbnail"
android:scaleType="fitCenter"/>
</RelativeLayout>
</TableRow>
This gets inflated by the following class:
public Cell(Context context) {
super(context);
addView(((LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE))
.inflate(R.layout.gallery_row_1, null));
}
When I inflate the cell, I also set an image to be used as a display, the problem is that the size of the image view is not staying as it should, the right edge is nowhere to be found, and the image is never displayed (probably way off to the right somewhere?), and I am not sure where my problem lies.
c = new Cell(this);
c.getImageView().setImageBitmap(BitmapFactory.decodeStream(assetManager.open("categories" + File.separator + sec + File.separator + filename)));
page.addView(c);
getImageView being a function in my Cell that returns the actual ImageView element.
I know the image is being placed in the ImageView, because when layout params are changed, I can see the image, just not sized appropriately.
The desired output should be a view, a dividing view on top, and an ImageView below, that fills the parent and is 100dp tall. The image, no matter the origional size, should be scaled and shown inside.
Also, if I comment out the line where I set the image to the ImageView, the layout bounds are correct, as viewed with Show Layout Bounds enabled.
My overall question is, why is my ImageView being re-sized when I apply an image.
Any and all help is greatly appreciated.
See this post on LayoutInflater for why your layout is getting mixed up. Since it seems your cell class is an inner class of some ViewGroup (since you're calling addView()), try using the following code:
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.gallery_row_1, this);
or
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.gallery_row_1, this, false);
addView (view);
instead of using
inflater.inflate(R.layout.gallery_row_1, null);
The inflate() call uses the second parameter (the container) to determine what type of LayoutParams to use to interpret the XML. If you pass null, all of the layout attributes are ignored. You should instead either call it with the actual container (which will automatically add it to the container) or call it with the container, and a third parameter telling it not to attach the view yet, and then do what you want with the inflated view.

How can I make a ViewGroup child match_parent when its sibling is GONE?

I have a layout whose root ViewGroup has two children only one of which is always visible. The other child's visibility will be set at runtime to View.GONE when not applicable.
When both children are visible, the heights are set to wrap_content and the layout looks great. The problem is that I'd like to expand the visible view to match_parent when the other is gone.
Is there any way to accomplish this or the equivalent?
You can change any View's layout like this:
view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
The constructor takes width then height as in: new LayoutParams(int width, int height).
Also there is a LayoutParams class for each type of ViewGroup. Make sure you import the one that refers your particular ViewGroup. So if your ViewGroup is a LinearLayout use:
import android.widget.LinearLayout.LayoutParams;
I tried unsuccessfully figuring this strategy out
I'm not certain where you had trouble, but this approach only requires a couple extras lines:
// When you want to show both views
view1.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
view2.setVisibility(View.VISIBLE);
...
// When you want to hide the second view
view1.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
view2.setVisibility(View.GONE);
If you hide / show the views multiple times you can save a reference to each LayoutParams object rather than repeatedly creating new objects.
Have you tried working with android:layout_weight?
I put together this small example. Below I added a picture showing both views visible (left) and how it looks like with view2 visibility set to GONE (right). As you see, view1 uses up all available space then.
<?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" >
<View
android:id="#+id/view1"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#ff0000" />
<View
android:id="#+id/view2"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#0000ff" />
</LinearLayout>

"Workspace" child views not filling height on Google "iosched" app

I'm playing around with the iosched app from Google I/O 2011. Looking at the ScheduleFragment, I'm testing a different view on the Workspace children for flinging the pages back and forth. However, I'm having trouble getting my child views to fill the parent. I added several background colors and some padding to show where everything is laying out. Here's my test...
I added a red background color to the "Workspace" item in fragment_schedule.xml like this...
android:background="#cc0000"
Then, instead of using blocks_content.xml for the child view, I created my own pending_content.xml that is simply a green-background LinearLayout (with fill_parent for height) and a blue-background TextView (also with fill_parent for height) with a simple text line.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="#+id/container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#00cc00"
android:padding="5dip"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="#+id/text_view"
android:background="#0000cc"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="Pending Content"
android:textColor="#ffffff"
/>
</LinearLayout>
I add my view just like the I/O app has "days"...
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_schedule, null);
mWorkspace = (Workspace) root.findViewById(R.id.workspace);
ShootView view = new ShootView();
view.index = mViews.size();
view.rootView = (ViewGroup) inflater.inflate(R.layout.pending_content, null);
view.label = "Pending";
mWorkspace.addView(view.rootView);
mViews.add(view);
And here's what I see when I view it on the device:
You'll see that the red Workspace fills the available parent space, but the green LinearLayout does not. What am I missing?
The problem is that during your inflation step:
view.rootView = (ViewGroup) inflater.inflate(R.layout.pending_content, null);
You lose the LayoutParams defined in your XML, and your view actually ends up with default layout parameters.
What you need to do is provide a root and simply not attach the inflated layout to the root during inflation:
view.rootView = (ViewGroup) inflater.inflate(R.layout.pending_content, mWorkspace, false);
This will allow the layout inflater to construct an appropriate set of LayoutParams for your child view from the parsed XML attributes.
I figured out a solution. I started debugging the onLayout in Workspace.java. In the child.layout function call, I changed child.getMeasuredHeight() to this.getMeasuredHeight() to use the height of the workspace instead.
Seems to work fine for the case of a page that is shorter than the workspace height as well as a child that is bigger (a long ListView) that is larger than the height of the workspace.

Categories

Resources