Android List View Items Alignment - android

I have a list view in which I add items dynamically. I want that some items ( of my choice) should align to the left hand side and some to the right hand side. Is this thing possible with the ListView of Android??
//Adapter
if (convertView == null) {
holder = new EventViewHolder();
if (type == 1) {
convertView = inflater.inflate(
R.layout.multi_line_list_item, null);
holder.mtvMessage = (TextView) convertView
.findViewById(R.id.tvMessage);
holder.mtvMessage.setGravity(Gravity.LEFT);
holder.mtvMessage.setBackgroundResource(R.drawable.chatbluebox);
convertView.setTag(holder);
}else{
convertView = inflater.inflate(
R.layout.multi_line_list_item, null);
holder.mtvMessage = (TextView) convertView
.findViewById(R.id.tvMessage);
holder.mtvMessage.setGravity(Gravity.RIGHT);
holder.mtvMessage.setBackgroundResource(R.drawable.chatgreenbox);
convertView.setTag(holder);
}
Please let me know if it can be done and suggest me a good solution?

android:stackFromBottom="true"
android:transcriptMode="alwaysScroll"
Add these lines in your listView xml entry..,.
And for right and left alignment, maintain two layouts xmls one right align and other left align(Whatever look you want) and then in getView() method of listAdapter set some condition and inflate these xml as you want
if (convertView == null)
if(some condition)
convertView = mInflater.inflate(R.layout.rightxml, null);
else
convertView = mInflater.inflate(R.layout.leftxml, null);
....

Have a look at the ListView modes stackFromBottom and transcriptMode those may do most of the work for you.
To align the items in the Cells left and right you can, for example set the gravity to left and right in your Adapters getView Method.

Use following.
adapter.notifyDataSetChanged();
And then
listView.setSelection(items.size()-1);
For gravity You need to set gravity dynamically in your getview() method.
FOr example :-
textview1.setGravity(Gravity.RIGHT);

Related

Android ArrayAdapter not properly converting Views

I have a custom ArrayAdapter for a ListView that uses a custom row layout, defined separately in XML. The layout is just three TextViews and an ImageView, put together in a RelativeLayout. To improve performance, the adapter uses a ViewHolder system like the one described here to convert existing Views instead of inflating new ones. In ArrayAdapter.getView(), the adapter is supposed to bold or unbold the first TextView, depending on a boolean.
When I first open the app, all of the TextViews are properly bolded or unbolded. However, if I scroll to the bottom of the ListView, then scroll back to the top, all of the title TextViews are bold, even if they aren't supposed to be. I think it must have something to do with converting existing views that are already bold, but I can't figure out what it is. I've debugged the app with Android Studio, and it runs just like I think it should -- when I scroll back up, the adapter properly bolds/unbolds things in the debug window, but they all seem to be bold on the app.
One thing I have noticed is that if I change the textStyle attribute of the TextView to "bold," all the title TextViews are bold from the beginning, and never change. It's only if I remove textStyle or set it to "normal" that the TextViews are normal at the start.
Here's getView() in the ArrayAdapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
PostShell shell = postShellList.get(getCount() - 1 - position); //I stack my ListView backwards, so index 0 is at the bottom
ViewHolder holder;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.row_layout, parent, false);
holder = new ViewHolder();
holder.firstLine = (TextView) convertView.findViewById(R.id.firstLine);
holder.secondLine = (TextView) convertView.findViewById(R.id.secondLine);
holder.thirdLine = (TextView) convertView.findViewById(R.id.thirdLine);
holder.image = (ImageView) convertView.findViewById(R.id.image);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.firstLine.setText(shell.postTitle);
if (shell.unread) {
holder.firstLine.setTypeface(holder.firstLine.getTypeface(), Typeface.BOLD);
} else {
holder.firstLine.setTypeface(holder.firstLine.getTypeface(), Typeface.NORMAL);
}
//convert other TextViews
}
My ViewHolder class is just a static class with a few TextViews and an ImageView.
And here's the relevant part of the code for the row layout I'm using:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="88dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="84dp"
android:paddingRight="16dp"
android:paddingTop="6dp"
android:id="#+id/firstLine"
android:ellipsize="end"
android:text="First"
android:textStyle="normal"
android:singleLine="true" />
<!-- other views -->
</RelativeLayout>
The problem seems to be that "unboldening" the text does not work with the following statement:
holder.firstLine.setTypeface(holder.firstLine.getTypeface(), Typeface.NORMAL);
The following snippet leaves out the holder.firstLine.getTypeface() and just uses a simpler variety of setTypeface(). Worked for me.
if (shell.unread) {
holder.firstLine.setTypeface(holder.firstLine.getTypeface(), Typeface.BOLD);
} else {
holder.firstLine.setTypeface(Typeface.DEFAULT);
}
PostShell shell = postShellList.get(getCount() - 1 - position); //I stack my ListView backwards, so index 0 is at the bottom
If the ListView asks for the element at a particular position, you'd better give it the element at that position or it's going to be confused. IF you want to alter the order of the items in the list, change the order of the list, don't try to trick ListView into rendering it in a different order.
You should store your views in the normal order and use android:stackFromBottom or setStackFromBottom().

Android Listview: imageview in first element

I've a custom listview in my chat application. It shows some people I've already chatted with. I want the first element in the listview to be an imageview that, when clicked, gives the user the opportunity to type a new person he wants to chat with. I've already implemented that (I don't want to use ListView header), by adding one more element to the listview and then inflate the imageview or the textview according to the position...
View v = convertView;
if (v == null) {
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
if (position == 0)
v = vi.inflate(R.layout.list_item_chat_list_header, parent, false);
else
v = vi.inflate(R.layout.list_item_chat_list, parent, false);
}
TextView tvName = ((TextView) v.findViewById(R.id.id_chat_list_name));
TextView tvPreview = ((TextView) v.findViewById(R.id.id_chat_list_preview));
if ( tvName != null && tvPreview != null ) {
ChatListElement p = getItem(position);
tvName.setText(p.name);
String preview = p.lastMessage;
if (preview.length() > 30)
preview = preview.substring(0, 30) + "...";
tvPreview.setText(preview);
}
return v;
But, when I run it, I get some of the views in the middle were also turned into imageviews... I think it has something to do with recycled views in listview, but I don't understand how to make it work.
Thank you very much
Step #1: Override getViewTypeCount() in your adapter to return 2
Step #2: Override getItemViewType() in your adapter to return 0 for position 0 (your ImageView) and 1 for everything else (your normal rows)
Step #3: Use getLayoutInflater(), called on your Activity, not LayoutInflater.from() (not technically related to your problem, but you'll thank me later for helping ensure that your custom themes work as expected)
Steps #1 and #2 will teach the ListView to maintain two object pools, one for each type of row, and it ensures that the row you get back for recycling is of the right type for the requested position.

Android ListView items reappering

I'm working on a ListView based app and I have a very weird problem, my ListItems are reappering and the correct item is not shown in the correct spot. For the sake of making this easy to understand I've set the text on each ListItem to be the same as it's position. I'm doing this in my adapters getView() call. If I have my Nexus 7 4 ListItems are visible. If I have a total of 10 ListItems then it will go like 0, 1, 3, 4, 0, 1, 2, 3, 4. This goes for all devices meaining that the number of items initially on screen + 1 will be correct while all other ListItems are rearrenged.
In which part of my code do you guys think my problem lies because right now I've been trying to fix this for hours and I'm clueless. All help is very much appreciated.
EDIT:
Here's my getView():
#Override
public View getView(int position, View convertView, ViewGroup parent) {
CountdownItem ci = mTitle.get(position);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, parent, false);
holder = new CountdownViewHolder();
holder.mTitle = (TextView) convertView.findViewById(R.id.textPrim);
holder.mSubtitle = (TextView) convertView
.findViewById(R.id.textSec);
holder.mDayProgress = (ProgressBar) convertView
.findViewById(R.id.day_progress);
holder.mMonthProgress = (ProgressBar) convertView
.findViewById(R.id.month_progress);
holder.mYearText = (TextView) convertView
.findViewById(R.id.year_text);
holder.day_help = (TextView) convertView
.findViewById(R.id.day_help);
holder.month_help = (TextView) convertView
.findViewById(R.id.month_help);
holder.setTitle(Integer.toString(position) + " Title");
holder.setSubtitle(ci.getSubtitle());
holder.fixImageAndText(position);
convertView.setTag(holder);
} else {
holder = (CountdownViewHolder) convertView.getTag();
}
return convertView;
}
You aren't using the ViewHolder pattern correctly. The following code needs to be moved outside the if/else clause and before return convertView:
holder.setTitle(Integer.toString(position) + " Title");
holder.setSubtitle(ci.getSubtitle());
holder.fixImageAndText(position);
This is the correct behaviour for the listview when it is reusing cells, the problem is that you only set the values when the cell is first created.
When convertView == null the listview has no cell to recycle. However, once it has created a few it can reuse them to display as you scroll.
What you need to do is set the title and subtitle even when convertView is not null. That way you're setting them for each new list position.
Yes, this is because android reuses views in lists, to increment performance and rendering speed.
The holder pattern is used to store views ids. After you retrieve them, you have to set the text you want to see inside.
For example, you retrieve your data (e.g. myDataArray[position]), and if it's all ok, you proceed setting title, subtitle, dayprogress, etc. with TextView's setText().

Android Widget: Add top margin to ListView in a widget

While this question may sound like a dupe of some others, the fact I am trying to do this in a widget significantly limits my ability to use the proposed solutions elsewhere.
Summarized: I would like to add spacing above the top-most item in the list and below the bottom-most item in order to offset them away from the title bar and bottom bar edge.
Essentially, I am trying to solve the same problem as Add margin above top ListView item (and below last) in Android, however, I cannot rely on having a reference to my ListView object in order to setHeader() or anything like that.
Is this really impossible to do in an Android widget?
I assume you are using an adapter for your ListView, so you are inflating additional listview layout. In a getView method, according to list item position (0 and last), place your bottom or top padding.
So ,here i have override function of adapter.From this function you can change or specify margin,height.Here you need to take object of Layout which you are using and from this you can change layout attributes.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.drawer_list_item, null);
}
if (position == 0) {//for first row
ImageView imgIcon = (ImageView) convertView.findViewById(R.id.icon);
TextView txtTitle = (TextView) convertView.findViewById(R.id.title);
RelativeLayout.LayoutParams relate = new RelativeLayout.LayoutParams(200, 200);
relate.setMargins(150, 0, 0, 0);
imgIcon.setLayoutParams(relate);
RelativeLayout.LayoutParams text = new RelativeLayout.LayoutParams(300, 100);
text.setMargins(150, 180, 0, 0);
}
return convertView ;
//HOPE IT HELP
in the adapter during getView() check if it's either position 0 or .getLength() and set LayoutParams on the convertView there

How to add Header in ListView at specific location and create custom view for list item

i am again here with one issue
i want to crate a custom view of list item with imageview and textview's and also i need to add header's on specific positions. i never used sectioned listview yet.
I need to add more than one textview and imageview in listitem and also i need to add header's at some random positions. please help me in solving this. i had googled it and i found some examples also but i am unable to customize it.
Thanks in advance.
Mahaveer.
I understood it a little bit. You should add more attribute like header in your model.
If your header = true and in your adapter class, then you have to inflate the layout header.xml. Otherwise, if header = false, then you should inflate your xml file i.e. (TextView,ImageView) as normal.
Here separator in my code is the same as your header
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
final recordModel model = records.get(position);
ViewHolder holder;
convertView = null;
holder = new ViewHolder();
if(records.get(position).getSeparator()==0){
convertView = inflater.inflate(R.layout.record_row, null);
convertView.setTag(holder);
holder.imageView = (ImageView) convertView
.findViewById(R.id.iconCallType);
holder.title = (TextView) convertView.findViewById(R.id.title);
holder.note = (TextView) convertView.findViewById(R.id.note);
holder.checkBox = (CheckBox) convertView.findViewById(R.id.check_box);
..........................
}else if(records.get(position).getSeparator()==1){
convertView = inflater.inflate(R.layout.separator, null);
convertView.setTag(holder);
holder.title = (TextView) convertView.findViewById(R.id.textSeparator);
holder.title.setText(records.get(position).getCallDay());
}
return convertView;
}
We do have a lot of amazing tutorials for the same, check some examples below:-
Android Section List
Android Amazing ListView
Do let us know, if you have to deal anu issue while doing it or have to go for any specific requirements to complete it.
You can add your own Header at any specific position using getItemViewType() and getViewTypeCount(). Here is a nice blog that explain everything about using these methods.

Categories

Resources