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"
Related
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"/>
I am looking for a way to modify my custom listadapter so that the TextViews will start at the end of the previous text views in the list.
Each section of text can vary in length, and they are usually several lines. Let's say these are two of my portions of text.
Text 1:
"Section 1: The tiger ran up to the log. He stopped for a moment to smell his surroundings."
Text 2:
"Section 2: He didn't smell anything. He continued on his journey."
With my current set up, these display like this(I've added line breaks to simulate the Android screen size and to emphasize what I mean):
Section 1: The tiger ran up to the log. He stopped for
a moment to smell his surroundings.
Section 2: He didn't smell anything. He continued on
his journey.
How I would like it to display, is like this:
Section 1: The tiger ran up to the log. He stopped for
a moment to smell his surroundings. Section 2: He
didn't smell anything. He continued on his journey.
Does that make sense? The problem is that the amount of Sections can vary, and I need this to work for each successive set of text. For example, Section 3 should continue on the same line as Section 2, if there is additional room.
Here is my current setup, though there isn't a lot here, it's pretty basic.
My ListView:
<LinearLayout
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/fragment_list_view"
android:paddingTop="2dp"
android:paddingBottom="2dp"
tools:context="com.name.appname.ActivityName"
>
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#null"
android:dividerHeight="0dp"
>
</ListView>
</LinearLayout>
My TextView:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/list_view_layout"
android:descendantFocusability="blocksDescendants">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="#string/default_text"
android:id="#+id/thetext"
android:layout_alignParentTop="true"
/>
</RelativeLayout>
My List Adapter:
public class MyListAdapter extends ArrayAdapter<ClassObject>
{
public MyListAdapter()
{
super(getActivity(), R.layout.listview_display_button, List);
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View itemView = convertView;
if (itemView == null)
{
itemView = getActivity().getLayoutInflater().inflate(R.layout.listview_display_button, parent, false);
}
TextView Text = (TextView) itemView.findViewById(R.id.thetext);
Text.setText(List.get(position).getText());
return itemView;
}
}
I have ListAdapter which fills list with TextView of category and RadioButton which is to be checked. So, the problem is that I want user to define which category he wants through List and when he clicks on RadioButton, others should be unchecked and so on. I need to set somehow the ID of this RadioButtons and I'm doing that in getView(...) method in ListAdapter but when it calls for second time that method, he doesn't find that RadioButton and I get error while trying to set ID of this RadioButton view. I was debugging it, and first time it finds the view through method findViewById, but second time it doesn't.
I think I might know the problem for it -> when second time it goes to find the view by ID, it can't find it since I've put already other Identifier on the first call, but how can I set unique identifiers for my RadioButtons in the list then?
Here is my code:
getView:
public View getView(int index, View view, ViewGroup parent) {
if (view == null){
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
view = inflater.inflate(R.layout.category_item, parent, false);
}
ListCategoryItem category = categories.get(index); // categories is list
TextView title = (TextView) view.findViewById(R.id.categoryTitle);
naziv.setText(kategorija.getNazivKategorije());
RadioButton radioBtn = (RadioButton) view.findViewById(R.id.categoryRadioButton);
radioBtn.setId(category.getIdCategory());
return view;
}
and here is my layout for category_item:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/categoryTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:paddingTop="5dp"
/>
<RadioButton
android:id="#+id/categoryRadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:textSize="15sp"
android:onClick="onRadioButtonClick"/>
So, how to set unique identifier to my RadioButtons in view properly or can I make somehow group of RadioButtons which will care for itself that when other one is checked, others to be unchecked - something how in HTML is solved up.
By using setId(), you are changing the identifier associated with the RadioButton that is used to find it in the view tree. You should probably be using setTag() instead, which is documented here. This method allows you to attach some opaque data object to the view that can be retrieved later using the getTag() method.
Look at the code :-
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
row = inflater.inflate(R.layout.country_row, parent, false);
}
return row;
}
The country row XML is :--
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="1" >
<TextView
android:id="#+id/nameOfCountry"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:text="Country" />
<CheckBox
android:id="#+id/checkBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.2"
android:gravity="right" />
Now my question is once I check few of the check boxes in the list view and the scroll the list view, many other check boxes are automatically checked....
I know there is problem in getView but I'm not able to figure out where....
Also the problem is solved if I don't reuse the convert view. But that is a dumb idea...
Any thoughts.....
That's because the ListView does recycling of views. Essentially, it reuses some views that go off screen to make the new ones on screen to help with performance. There are 2 ways of dealing with this:
Set the values of the views before you return the row. For example, you would set the nameOfCountry and whether or not the checkbox is checked before the return view line. To do this though, you need to keep track of what is checked.
Don't use the convertview and just inflate a new view every time. This may result in a performance hit, but as long as the list isn't too long it shouldn't be too noticable (at least in my experience). Simply igonre the convertview value
You have to set the state of the checkbox explicitly if you reuse an old View.
I have a list.
When you click on element, it becomes selected, and should be expanded vertically to displat some more data.
I am trying to accomplish this by adding to each element's layout "Details" view which is hidden by dafault and is set to VISIBLE onClick.
The only problem that the height of element isn't changed.
If I try to it like this:
holder.line_view
.setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, dip(
convertView.getContext(), 30)));
then I get unknown exception.
Just
holder.details_pane.setVisibility(View.VISIBLE);
doesn't work, the size isn't changed.
Please advise.
Layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/line_view">
<TextView
android:id="#+id/desc"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="Description" />
<TextView
android:text="LALALA"
android:id="#+id/detailed_desc"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
In adapter I try:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
...
switch (getItemViewType(position)) {
case TYPE_ITEM_EXPANDED:
holder.details_pane.setVisibility(View.VISIBLE);
...
case TYPE_ITEM_NORMAL:
holder.details_pane.setVisibility(View.GONE);
}
"doesn't work, the size isn't changed"
something to try if you allow your view to be rotated: make your view redraw itself and see if the row is bigger.
It might be that you just need to invalidate the listview so that it redraws. Possibly invalidate the row.
maybe it's even as easy as calling notifyDataSetChanged(); on your custom listview adapter
I have no idea about the issue of you code. but you should try this
com.android.widget.ExpandableListView
com.android.widget.ExpandableListAdapter
this is designed for your requirement and shipped with the OS