I have to admit I'm a newbie in Android and my ExpandableListView is causing me a lot of trouble. I've figured it's the adapter which isn't working properly. I'm using a class which extends BaseExpandableListAdapter.
From logging I know this much:
The list I hand over to the constructor of the adapter is filled correctly. getGroupCount returns 1 (yes, there's only 1 group) and getChildrenCount returns 18 (as expected). The method getGroupView is called (Log.d...) but getChildView isn't - not when logging at the very start of this method and not while debugging (didn't reach the breaking point).
There are no error messages - it's just the ExpandableListView quietly not expanding.
Any idea what went wrong? Do I need a ViewHolder or is it not inflating the group properly? I'm totally lost...
Part of my code:
package de.cimitery.android.cimitery;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.CheckBox;
import android.widget.TextView;
public class ExpandableAdapter extends BaseExpandableListAdapter {
private List<GroupCat> catList;
private Context ctx;
NewGraveActivity app;
public ExpandableAdapter(List<GroupCat> catList, Context ctx, NewGraveActivity app) {
this.catList = catList;
this.ctx = ctx;
this.app = app;
}
#Override
public Object getGroup(int groupPosition) {
return catList.get(groupPosition);
}
#Override
public int getGroupCount() {
Log.d("ExAdapter getGroupCount", "" + catList.size());
return catList.size();
}
#Override
public long getGroupId(int groupPosition) {
return catList.get(groupPosition).hashCode();
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
Log.d("ExAdapter getGroupView", "Start");
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater)ctx.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.group_layout, parent, false);
}
TextView groupName = (TextView) v.findViewById(R.id.groupName);
GroupCat cat = catList.get(groupPosition);
groupName.setText(cat.getGroupName());
return v;
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return catList.get(groupPosition).getItemList().get(childPosition);
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return catList.get(groupPosition).getItemList().get(childPosition).hashCode();
}
#Override
public View getChildView(final int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
Log.d("ExAdapter getChildView", "Start");
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater)ctx.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.item_layout, parent, false);
}
CheckBox itemCheck = (CheckBox) v.findViewById(R.id.itemCheck);
TextView itemName = (TextView) v.findViewById(R.id.itemName);
if (app.selected.containsKey((groupPosition))==true)
itemCheck.setChecked(true);
else
itemCheck.setChecked(false);
Category child = catList.get(groupPosition).getItemList().get(childPosition);
Log.d("ExAdapter getChildView", child.getName());
itemName.setText(child.getName());
itemCheck.setOnCheckedChangeListener(new CheckListener(childPosition, app));
return v;
}
#Override
public int getChildrenCount(int groupPosition) {
int size = catList.get(groupPosition).getItemList().size();
System.out.println("number of children for group ["+groupPosition+"] is ["+size+"]");
return size;
}
}
group-layout:
<?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" >
<TextView
android:id="#+id/groupName"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="15dip" />
<TextView
android:id="#+id/groupDescr"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="8dip" />
</LinearLayout>
item layout:
<?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" >
<CheckBox
android:id="#+id/itemCheck"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="#+id/itemName"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
layout with exp. listview:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ExpandableListView
android:id="#+id/expandableListView1"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_marginTop="10dp" >
</ExpandableListView>
<Button
android:id="#+id/buttonNewGrave"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/buttonNewGrave" />
</LinearLayout>
</ScrollView>
First thing:
You should not use any scrolling component like expandable list, inside a scroll view here's why Listview inside ScrollView is not scrolling on Android.
Second thing:
Height of ExpandableListView should be match_parent. In your case you have taken Expandable ListView within Linear Layout whose height is wrap_content, change it to match_parent.
I had faced the same problem and I resolved that problem by following the same.
Related
I want to create an expandable list with viewpagers as subviews. The problem is now that with my code it calls the getChildView method twice and thus creates my viewpager twice.
I also tried it with the TextView (which is the sample code I posted here for convenience) to simplify the code but the same issue arose.
My best guess is it has something to do with the height property of the layouts but no matter how i changed it, I couldn't resolve the issue.
Please help. I am totally lost. I used a tutorial for this code and I seem to be the only who has that issue judging from the youtube comment section. (https://www.youtube.com/watch?v=jZxZIFnJ9jE)
(If you need any other part of the code please let me know.)
delete.xml file looks like this
<?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:id="#+id/sukahead">
<TextView
android:id="#+id/suka"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="suka"
android:paddingLeft="?android:attr/expandableListPreferredChildPaddingLeft"
android:paddingStart="?android:attr/expandableListPreferredChildPaddingLeft"
/>
</LinearLayout>
sublist.xml
<?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="wrap_content"
android:padding="8dp" android:background="#color/white"
android:id="#+id/sublist">
<TextView
android:id="#+id/dict_entry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="?android:attr/expandableListPreferredChildPaddingLeft"
android:paddingStart="?android:attr/expandableListPreferredChildPaddingLeft"
android:textSize="16sp"
android:textColor="#color/colorAccent"
android:text="test"
/>
</LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:background="#color/colorPrimary">
<EditText
android:id="#+id/search_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/search_hint"
android:layout_margin="15dp"
android:padding="5dp"
app:layout_constraintTop_toTopOf="parent"
android:background="#color/white"
android:adjustViewBounds="true"
android:maxLines="1"
android:inputType="text"
android:onClick="lookup_word"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/search_bar"
android:orientation="horizontal">
<ExpandableListView
android:id="#+id/search_result_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#333"
android:dividerHeight="1dp"
android:background="#color/white"
android:layout_margin="15dp"/>
</LinearLayout>
</RelativeLayout>
ExpandableListAdapter.java
package com.lunaticcoding.linguodict;
import android.content.Context;
import android.graphics.Typeface;
import android.support.v4.view.ViewPager;
import android.text.Layout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
import java.util.HashMap;
import java.util.List;
public class ExpendableListAdapter extends BaseExpandableListAdapter {
private Context context;
private List<String> data;
private HashMap<String, String[]> listHashMap;
private LayoutInflater inflater;
private String pageData[];
public ExpendableListAdapter(Context context, List<String> list, HashMap<String, String[]> hashMap) {
this.context = context;
this.data = list;
this.listHashMap = hashMap;
}
#Override
public int getGroupCount() {
return data.size();
}
#Override
public int getChildrenCount(int groupPosition) {
return listHashMap.get(data.get(groupPosition)).length;
}
#Override
public Object getGroup(int groupPosition) {
return data.get(groupPosition);
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return listHashMap.get(data.get(groupPosition))[childPosition];
}
#Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
#Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
String headerTitle = (String) getGroup(groupPosition);
if(convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.sublist, null);
}
TextView textView = (TextView) convertView.findViewById(R.id.dict_entry);
textView.setText(data.get(groupPosition));
return convertView;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
final String childText = (String)getChild(groupPosition, childPosition);
if(convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.delete, null);
}
TextView textView = (TextView) convertView.findViewById(R.id.suka);
return convertView;
}
#Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
MainActivity (only OnCreate)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
searchBar = (EditText) findViewById(R.id.search_bar);
searchResults = (ExpandableListView) findViewById(R.id.search_result_list);
list_results = new ArrayList<>();
examples_results = new HashMap<>();
list_results.add("test1");
list_results.add("test2");
list_results.add("test3");
String pageData1[] = new String[]{"si", "siiii"};
String pageData2[] = new String[]{"jifasfa", "sfasdfasiii"};
String pageData3[] = new String[]{"jifasfa", "sfasdfasiii"};
examples_results.put(list_results.get(0), pageData1);
examples_results.put(list_results.get(1), pageData2);
examples_results.put(list_results.get(2), pageData3);
searchResultsAdapter = new ExpendableListAdapter(this, list_results, examples_results);
searchResults.setAdapter(searchResultsAdapter);
lastExpandedPosition = -1;
searchResults.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
#Override
public void onGroupExpand(int groupPosition) {
if(lastExpandedPosition != -1 && (lastExpandedPosition != groupPosition)){
searchResults.collapseGroup(lastExpandedPosition);
}
lastExpandedPosition = groupPosition;
}
});
}
In the sub_list.xml the layout_height is "wrap_content". Change it to a fixed height (some dp) or match_parent and it will work.
Reason:
wrap_content has to calculate the height of the layout content it has to match thus reloading the layout afterwards -> creating the list more than once.
I have ListView at my fragment where I try to select some items by LongClick.
At my screen I can see 8 items ( on another smartphone I can see 6 items.) When I have a lot items in my ListView ( for example 23) and I LongClick on a first item as a result I see changed image, but if I scroll down I can see that 10 and 19 items has changed image too ( like they has been checked ). At the another smartphone after LongClick the first item I see change 8 and 16 too and etc). As you can see I get change ListView items images just after the same numbers of items as can present my smartphone. The real status of "additional" items not changed, only their image view. It's the strange behavior of ListView, which duplicate changing image of items view at each group ( group means the number ListView items a multiple the number of items which the smartphone can display simultaneously)
Whats wrong in my code or how to avoid this unexpected behavior of ListView?
Thanx
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import ru.someCode.R;
public class ListItems extends ListFragment {
private ListView lv;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_list, null);
lv = getListView();
return rootView;
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapter, View view,
int position, long id) {
Log.d("MY", "Checked");
ImageView imageView = ((ImageView) view.findViewById(R.id.operImg));
ImageView imageViewCheck = ((ImageView) view.findViewById(R.id.operImgCheck));
if (lv.isItemChecked(position)) {
lv.setItemChecked(position, false);
imageView.setVisibility(View.VISIBLE);
imageViewCheck.setVisibility(View.GONE);
} else {
lv.setItemChecked(position, true);
imageView.setVisibility(View.INVISIBLE);
imageViewCheck.setVisibility(View.VISIBLE);
}
return true;
}
});
}
}
---- fragment_list.xml ----
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="6dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/listContainer">
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dividerHeight="1dip"
android:divider="#color/listDev"
android:footerDividersEnabled="true"/>
<TextView
android:id="#id/android:empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="16sp"
android:gravity="center" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/progressContainer"
android:layout_centerInParent="true"
android:gravity="center"
android:visibility="gone">
<ProgressBar style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
---- adapter code part ---
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.history_list_group, null);
holder = findViewsById(convertView);
convertView.setTag(holder);
if (lv == null) {
lv = (ListView) parent;
}
} else {
holder = (ViewHolder) convertView.getTag();
}
SetDataView(holder, position);
return convertView;
}
---- history_list_group.xml --
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/circle"
android:id="#+id/operImgLayout"
android:layout_gravity="center_vertical"
android:layout_margin="6dp">
<ru.phone4pay.phone4pay.extlib.MLRoundedImageView
android:id="#+id/operImg"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="#drawable/ic_action_1"/>
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:id="#+id/operImgCheck"
android:src="#drawable/ic_action_tick"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:visibility="gone"/>
</RelativeLayout>
</LinearLayout>
ListView recycles views, so I was wrong code. My decisions
--- at ListFragment ---
private ListView lv;
getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapter, View view,
int position, long id) {
lv.setItemChecked(position, !lv.isItemChecked(position));
mAdapter.setCheckedItems(position, lv.isItemChecked(position));
return true;
}
});
--- at adapter --
private boolean [] checkedItems;
public void setCheckedItems(int position, boolean state){
checkedItems[position] = state;
notifyDataSetChanged();
}
public void unCheckAllItems(){
for (int i=0; i<checkedItems.length; i++){
checkedItems[i] = false;
}
}
private void SetDataView(ViewHolder holder, int position){
if (checkedItems[position]){
holder.operImgCheck.setVisibility(View.VISIBLE);
holder.operImg.setVisibility(View.INVISIBLE);
} else {
holder.operImgCheck.setVisibility(View.INVISIBLE);
holder.operImg.setVisibility(View.VISIBLE);
}
}
Main reason of problem: I should change and rebuild adapter but don't change items from ListView !!! Don't use access to ListView items by ListView for changing them.
I want to make listview same like instagram...(Sectionised)
I searched in google and find some examples, but it is not working properly as I need.
This is the link i searched : Link 1 and Link 2. But in the first link I coudn't find any solution for instagram-like listview.
As for fhe second link, I made a demo and I run it and it works perfectly. The only problem is that when I put two textviews in the header then it is not working .
If you can help me regarding this then it would be great for me..
This demo from Second Link..
package com.example.Section_Listview;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class InstaHeaderActivity extends Activity implements AbsListView.OnScrollListener{
ListView list;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
list = (ListView) findViewById(R.id.list);
list.setAdapter(new Adapter(this));
list.setOnScrollListener(this);
}
public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount)
{
//the listview has only few children (of course according to the height of each child) who are visible
for(int i=0; i < list.getChildCount(); i++)
{
View child = list.getChildAt(i);
ViewHolder holder = (ViewHolder) child.getTag();
//if the view is the first item at the top we will do some processing
if(i == 0)
{
boolean isAtBottom = child.getHeight() <= holder.header.getBottom();
int offset = holder.previousTop - child.getTop();
if(!(isAtBottom && offset > 0))
{
holder.previousTop = child.getTop();
holder.header.offsetTopAndBottom(offset);
holder.header.invalidate();
}
} //if the view is not the first item it "may" need some correction because of view re-use
else if (holder.header.getTop() != 0)
{
int offset = -1 * holder.header.getTop();
holder.header.offsetTopAndBottom(offset);
holder.previousTop = 0;
holder.header.invalidate();
}
}
}
public void onScrollStateChanged(AbsListView view, int scrollState) {}
private static class Adapter extends ArrayAdapter<String> {
public Adapter(Context context) {
super(context, R.layout.row, R.id.header);
for(int i=0; i < 50; i++){
add(Integer.toString(i));
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
if(convertView == null)
{
convertView = LayoutInflater.from(getContext()).inflate(R.layout.row, parent, false);
ViewHolder holder=new ViewHolder();
holder.header = (TextView) convertView.findViewById(R.id.header);
convertView.setTag(holder);
}
ViewHolder holder = (ViewHolder) convertView.getTag();
holder.header.setText(getItem(position));
return convertView;
}
}
public static class ViewHolder
{
TextView header;
int previousTop = 0;
}
}
main.xml
<?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="fill_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</ListView>
</LinearLayout>
child_header.xml
<?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" >
<TextView
android:id="#+id/childHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="2dp"
android:text="childTest" />
</LinearLayout>
row.xml
<?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"
android:orientation="vertical" android:background="#FFFFFF">
<ListView
android:id="#+id/childList"
android:layout_width="fill_parent"
android:layout_height="150dp"
android:layout_alignParentLeft="true"
android:layout_below="#+id/header"
android:layout_marginTop="16dp" >
</ListView>
<TextView
android:id="#+id/header"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:padding="12dp"
android:text="Deneme Row"
android:textColor="#ffffff"
android:background="#000000"/>
</RelativeLayout>
First of all, you can't have two public classes in one file, so move
public class ViewHolder {
TextView header;
int previousTop = 0;
}
to a seperate file. And while you're at it, remove the static modifier, it's not allowed.
To display a second TextView in your header row, you have to declare it in row.xml:
<?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"
android:background="#FFFFFF"
android:orientation="vertical" >
<ListView
android:id="#+id/childList"
android:layout_width="fill_parent"
android:layout_height="150dp"
android:layout_alignParentLeft="true"
android:layout_below="#+id/header"
android:layout_marginTop="16dp" >
</ListView>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<TextView
android:id="#+id/header"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#000000"
android:padding="12dp"
android:textColor="#ffffff" />
<TextView
android:id="#+id/header2"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:background="#000000"
android:padding="12dp"
android:text="second textview"
android:textColor="#ffffff" />
</LinearLayout>
</RelativeLayout>
This modified row.xml will give you a layout like this:
To set the content of the second textview, change your ViewHolder class to:
public class ViewHolder {
TextView header;
TextView header2;
int previousTop = 0;
}
and change your getView-method in your activity to:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.row, parent, false);
ViewHolder holder = new ViewHolder();
holder.header = (TextView) convertView.findViewById(R.id.header);
holder.header2 = (TextView) convertView.findViewById(R.id.header2);
convertView.setTag(holder);
}
ViewHolder holder = (ViewHolder) convertView.getTag();
holder.header.setText(getItem(position));
holder.header2.setText("whatever you want");
return convertView;
}
I've been through every stack discussion on this I could find, along with about a dozen tutorials. I'm just not getting it. I'm using 'getItemViewType' to determine which layout I should use. Here's where I run into a problem (and maybe the way I'm getting the position is the root issue, not sure):
What I'm doing is getting the first character of the contact's name at position x. If it's different than the first character in position x-1, I know that it's the next letter in the list and it needs a section header, which would be inserted ABOVE the current list item. How do I get my adapter to add a new layout in position x-1?
This is my adapter code. I've stripped the code which was causing the app to force close, which leaves me with just the 1 layout. I can't figure out how to insert the 'section' layout at position x-1. Below the adapter code I threw in the xml for my 2 layouts. Let me know if you need anything else. Thanks in advance.
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class ContactNameAdapter extends BaseAdapter {
public static final int CONTACT_NAME = 0;
public static final int ALPHA_HEADER = 1;
private static final int NUMBER_OF_LAYOUTS = 2;
Context context;
private ArrayList<ListItemDetails> sItemDetailsArrayList;
public ContactNameAdapter(ArrayList<ListItemDetails> data, Context context) {
sItemDetailsArrayList = data;
this.context = context;
}
#Override
public int getCount() {
return sItemDetailsArrayList.size();
}
#Override
public ListItemDetails getItem(int position) {
return sItemDetailsArrayList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getViewTypeCount() {
return NUMBER_OF_LAYOUTS;
}
#Override
public int getItemViewType(int position) {
if (position != 0) {
if (getItem(position).getName().toUpperCase().charAt(0) == getItem(
position - 1).getName().toUpperCase().charAt(0)) {
return CONTACT_NAME;
} else {
return ALPHA_HEADER;
}
} else {
return ALPHA_HEADER;
}
}
#Override
public View getView(int position, View view, ViewGroup parent) {
ImageView mImageView;
TextView mTextView;
if (view == null) {
LayoutInflater layoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = layoutInflater.inflate(R.layout.contactlistlayout, null);
mImageView = (ImageView) view.findViewById(R.id.ivContactPhoto);
mTextView = (TextView) view.findViewById(R.id.textView1);
view.setTag(new ViewHolder(mImageView, mTextView));
} else {
ViewHolder viewHolder = (ViewHolder) view.getTag();
mImageView = viewHolder.mImageView;
mTextView = viewHolder.mTextView;
}
ListItemDetails listItemDetails = getItem(position);
mTextView.setText(listItemDetails.getName());
mImageView.setImageBitmap(listItemDetails.getImage());
if (listItemDetails.getImage() == null) {
mImageView.setImageResource(R.raw.default_contact);
}
return view;
}
private static class ViewHolder {
public final TextView mTextView;
public final ImageView mImageView;
public ViewHolder(ImageView mImageView, TextView mTextView) {
this.mImageView = mImageView;
this.mTextView = mTextView;
}
}
}
list layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/contactView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:paddingLeft="2dp"
android:textAppearance="?android:attr/textAppearanceMedium" />
<ImageView
android:id="#+id/ivContactPhoto"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false" />
</RelativeLayout>
section layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layoutView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants"
android:orientation="vertical" >
<TextView
android:id="#+id/tvAlphaHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:paddingBottom="10dp"
android:paddingLeft="2dp"
android:paddingTop="10dp"
android:textAppearance="?android:attr/textAppearanceSmall" />
<ImageView
android:id="#+id/ivSectionLine"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#android:color/holo_blue_light"
android:focusable="true" />
</LinearLayout>
I've looked at a bunch of tutorials that ended up confusing me more than helping me, but I found this one to be great. If you've been around the world on this like I have, take a look at this tutorial :)
http://codelikes.blogspot.com/2012/04/android-alphabet-listview-like-contacts.html?zx=d40863f078ab91b4
I try to use GridLayout, to have 4 text views (different string length) being displayed as same size, within same row of TableLayout.
Here is my XML code.
<?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="?android:attr/listPreferredItemHeight"
android:padding="6dip">
<ImageView
android:id="#+id/color_label"
android:layout_width="12dip"
android:layout_height="fill_parent"
android:layout_marginRight="6dip"
android:background="#ffffff" />
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns="1">
<TableRow>
<TextView
android:id="#+id/toptext"
android:gravity="left"
/>
<TextView
android:id="#+id/bottomtext"
android:gravity="right"
/>
</TableRow>
<View android:layout_height="2dip"
android:background="#FF909090" />
<TableRow>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/myGrid"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:numColumns="4"
/>
</TableRow>
</TableLayout>
</LinearLayout>
and here are my adapter code for the row of list view.
package org.yccheok.jstock.widget;
import java.util.ArrayList;
import org.yccheok.jstock.activity.R;
import org.yccheok.jstock.portfolio.Order;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.TextView;
public class OrderAdapter extends ArrayAdapter<Order> {
private ArrayList<Order> items;
public OrderAdapter(Context context, int textViewResourceId, ArrayList<Order> items) {
super(context, textViewResourceId, items);
this.items = items;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.custom_row_view, null);
}
Order o = items.get(position);
if (o != null) {
TextView tt = (TextView) v.findViewById(R.id.toptext);
TextView bt = (TextView) v.findViewById(R.id.bottomtext);
if (tt != null) {
tt.setText(o.getOrderName());
}
if (bt != null) {
bt.setText(o.getOrderStatus());
}
}
GridView grid = (GridView) v.findViewById(R.id.myGrid);
grid.setAdapter(new ImageAdapter(this.getContext()));
return v;
}
private class ImageAdapter extends BaseAdapter {
private Context mContext;
public ImageAdapter(Context c) {
mContext = c;
}
public int getCount() {
return 4;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
TextView textview = new TextView(mContext);
textview.setText("Hello");
return textview;
}
}
}
However, I am getting pretty strange result. (Highlight in red)
What my expectation is something like this. (Highlight in red)
Does this mean I can't use GridLayout in the row of TableLayout?
I don't know if this is the source of your problem or not, but I believe that all elements in a TableRow should be given a column number (e.g. android:layout_column="1").