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"/>
Related
I have a layout that contains a TextView that looks like this
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/visual_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor=?android:attr/colorAccent
android:maxLines="3"
android:gravity="center_vertical" />
I have specified an overlay directory and I'm attempting to overlay the layout file using a similar file except with some minor differences
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/visual_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor=?android:attr/colorPrimary
android:maxLines="3"
android:gravity="top" />
My application builds successfully, however, I'm seeing a NullPointerException during runtime when my Java code tries to set the text of the TextView
private void setVisualText(View someView) {
View view = getLayoutInflater().inflate(R.layout.myLayout, someView, false);
TextView myText = (TextView)view.findViewById(R.id.visual_text);
myText.setText(R.string.myString);
}
The exception happens only with the overlay file and the code runs fine without the overlay. Does anyone know why myText is null and why it's not finding the view correctly? My guess is it's related to the ID but I'm not sure why it's not resolving correctly.
So you have a TextView and an overlaying TextView?
If so, you should not use the same ids. Ids should be used only once.
Why are you calling?
getLayoutInflater().inflate(R.layout.myLayout, someView, false);
If you want to get a view from the main contentView, you can just use:
findViewById(id);
because if you want to attach the inflated view to the root you have to call:
getLayoutInflater().inflate(R.layout.myLayout, someView, true);
please try it with (..true).
by using the line above, you are getting the contentView view.
I wrote a small function
private void addTabIndicators(int tabCount){
LinearLayout indicatorsContainer = (LinearLayout)findViewById(R.id.indicators_container);
for(int i = 0; i<tabCount; i++){
ImageView indicator = (ImageView)this.getLayoutInflater().inflate(R.layout.tab_indicator, null);
indicatorsContainer.addView(indicator);
}
}
that is supposed to add circles to the linearlayout in my activity based on how many tabs are in the pager adapter. Everything would be cool BUT, the imageviews i add instead of beeing the size declared in the xml layout, are being resized to 1x1px... Any ideas where i could go wrong? Here are the layouts for the indicator and linear layout
tab_indicator.xml:
<?xml version="1.0" encoding="utf-8"?>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_margin="8dp"
android:src="#drawable/floating_button_background"/>
The indicators container:
<LinearLayout
android:layout_marginBottom="16dp"
android:orientation="horizontal"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:id="#+id/indicators_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</LinearLayout>
The fault might be here
ImageView indicator = (ImageView)this.getLayoutInflater().inflate(R.layout.tab_indicator, null);
You need to pass the root view of your image view to provide the layouts defined in your XML. If you pass null instead, default layoutparams are set.
Place
ImageView indicator = (ImageView)this.getLayoutInflater().inflate(R.layout.tab_indicator, your root view of image view,false);
This is a very common mistake. Never pass null except you really know what you are doing.
Read more here:
http://developer.android.com/reference/android/view/LayoutInflater.html
Hope it helps
So I am rather confused right now. I am using an XML layout so I can show an empty view like so:
<?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" >
<RelativeLayout
android:id="#android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="#string/samples_empty"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true" >
</ListView>
</RelativeLayout>
As you have probably seen a billion times here on so.
So I do setContentView(R.layout.foo) and it works the first time, but if I return to this Activity (As in onPause has been called and then onResume) I get this:
I call notifyDataSetChanged(); on the adapter and that works fine, what I don't get is why its being drawn twice?
Its not like I am creating a new ListView and then adding it to the view, I'm sure I would know about it if I was.
The getView method of the adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
RecordView av;
if(convertView == null){
av = new RecordView(mCtx, this, mRecords[position], position);
}else{
av = (RecordView) convertView;
av.setRecord(mRecords[position]);
}
return av;
}
This would be what it would look like normally...
NOTE
This doesn't seem to be happening every single time, and doesn't happen on a single event happening, but when it does, its when I return from another screen.
UPDATE
I noticed that when I had another activity on top (something that was transparent, like facebook chat heads, then I could see that the problem had occurred then, It doesn't seem to happen on onResume, but more likely on onPause which I actually don't do anything in.
You have this problem because you are dynamically create the row view each time while the convertview still has the old view existing and it is being reused. To get around this problem, you should give an id to every view (that is, every child view in your RecordView)when you dynamically create them, for example a child textview in your RecordView class should be instantiated like this
TextView tv = new TextView(this.getContext());
tv.setId(1);
...
Then, in your getView:
if(convertView == null){
av = new RecordView(mCtx, this, mRecords[position], position);
}else{
av = (RecordView) convertView;
av.findViewById(1).setText(mRecords[position]);
}
assuming your mRecords holds an array of String. If you have variant layout for different rows, you can provide a type to each view. See this for further details.
try changing android:layout_height="wrap_content" of listview to android:layout_height="fill_parent"
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.
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.