Horizontal ScrollView in List View Item Android - android

I have a list view with 20 rows and I want to setup a horizontal scrollview for every row item in list view, as each row contains more than one item.
Here is my code :
<?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="wrap_content"
android:orientation="horizontal" >
<HorizontalScrollView
android:id="#+id/hor_scroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none" >
<LinearLayout
android:id="#+id/mainLinear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
Inner Row Layout which is to be replicated in a row any number of times
<ImageView
android:id="#+id/icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginRight="6.0dip"
android:src="#drawable/ic_launcher" />
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:text="Example Value"
android:textAppearance="?android:textAppearanceMedium" />
BaseAdapter
public class HorizontalListViewAdapter extends BaseAdapter {
private Context context;
private ArrayList<ArrayList<DwivediJi>> dataSet;
public HorizontalListViewAdapter(Context context) {
this.context = context;
}
#Override
public int getCount() {
return 20;
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
#Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.horizontal_list_item, null,false);
LinearLayout mainLinnerLayout=(LinearLayout)convertView.findViewById(R.id.mainLinear);
for (int i = 0; i <5; i++) {
View additionView = inflater.inflate(R.layout.inner_layout_file, null,false);
LinearLayout innerLinnerLayout=(LinearLayout)additionView.findViewById(R.id.inner_layout);
mainLinnerLayout.addView(innerLinnerLayout);
}
return convertView;
}
class ViewHolder {
TextView tv_titleExample;
HorizontalScrollView hzView;
LinearLayout linear_layout,main_linear_layout;
}
}
My Problem
Look at the screenshot attached. My problem is that more than one view is showing at one time in each row.
I want that only one view should show to the user at one time and for the rest all the user has to do is swipe left to right or right to left.

Note: Not an ideal solution, but should provide what you want..
Another Note: This may make your listview slightly janky, depending on the layout-complexity
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.horizontal_list_item, null,false);
LinearLayout mainLinnerLayout=(LinearLayout)convertView.findViewById(R.id.mainLinear);
for (int i = 0; i <5; i++) {
View additionView = inflater.inflate(R.layout.inner_layout_file, null,false);
LinearLayout innerLinnerLayout=(LinearLayout)additionView.findViewById(R.id.inner_layout);
// If the width varies for each innerLinnerLayout, then remove the if block & always calculate padding value
// padding is an integer initialized to -1 in the constructor
if (padding == -1) {
int width = context.getResources().getDisplayMetrics().widthPixels;
innerLinnerLayout.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
padding = width - additionView.getMeasuredWidth();
}
// I've set padding to right only, but you could center it by giving left and right padding of value=(padding/2)
innerLinnerLayout.setPadding(0, 0, padding, 0);
mainLinnerLayout.addView(innerLinnerLayout);
}
return convertView;
}

The problem is with your adapter as:
getCount() from your adapter must return the total number from list. Returning 20 is not valid in your context - and you seem to have 20 items in your list. You should return dataSet.size();
getItem() should return the item from the model data structure, in this case:
Below
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return dataSet.get(position);
}
Also, your getView method must return the view that displays the model data at given at position parameter. Returning a ViewGroup with non-meaningfull dummy data is what you currently have. You should get the ArrayList<DwivediJi> from parameter position (through dataSet.get(position)) and construct/inflate a View that displays properly this data structure item.

Change inner layout width to match_parent. This should help you
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="#+id/icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginRight="6.0dip"
android:src="#drawable/ic_launcher" />
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:text="Example Value"
android:textAppearance="?android:textAppearanceMedium" />
</LinearLayout>
Seems you are adding your inner layout in this LinearLayout
<LinearLayout
android:id="#+id/mainLinear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
</LinearLayout>
Did you try changing its width to match_parent too??

Use scrollview in xml layout and then dynamically create HorizontalScrollView inside for loop:
example :
for(int i.......) //number of HorizontalScrollView needed
{
HorizontalScrollView mainlinear = new HorizontalScrollView(
getApplicationContext());
for(int i.......) //number of items wants to add in HorizontalScrollView
{
// adding any widgets as per your requirements
}
mainlinear.addView(Widgetname);
scroll.addView(mainlinear);
}

Related

Custom listview is not showing and getView is not called

I have problem that my list view is not showing and the getView method never invoked
here is my list view inside the onCreate in the MainActivity
l = (ListView) findViewById(R.id.listvv);
CustomAdapter adapter = new CustomAdapter(MainActivity.this, maainimg);
l.setAdapter(adapter);
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ads="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#color/white"
tools:context=".MainActivity">
<ListView
android:id="#+id/listvv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:divider="#b4be"
android:dividerHeight="2dp"></ListView>
<LinearLayout
android:id="#+id/ad_holder"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center|bottom"
android:layout_alignParentBottom="true">
<com.google.android.gms.ads.AdView
android:id="#+id/adView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
ads:adSize="BANNER"
ads:adUnitId="#string/BottomBanner">
</com.google.android.gms.ads.AdView>
</LinearLayout>
</LinearLayout>
and here is my CustomAdapter Class it is inside the MainActivity
public class CustomAdapter extends ArrayAdapter<String> {
int[] img;
Activity activity;
ImageButton imageButton;
public CustomAdapter(Activity act, int [] images) {
super(act, R.layout.custom_row);
this.activity=act;
this.img=images;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.d("getView","Called!");
View row = convertView;
if(row==null){
LayoutInflater inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.custom_row, parent, false);
imageButton = (ImageButton) row.findViewById(R.id.preview);}
imageButton.setImageResource(img[position]);
Log.d("added",position+"");
if (getSelectedcolor() == 0) {
imageButton.setColorFilter(Color.RED);
setSelectedcolor(Color.RED);
} else {
imageButton.setColorFilter(Color.parseColor(colorToHexString(getSelectedcolor())));
}
return row;
}
}
and the custom_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background">
<ImageButton
android:id="#+id/preview"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="10dp"
android:src="#drawable/ic_1_red"
android:scaleType="fitXY"
android:background="#drawable/roundedbutton"
/>
</LinearLayout>
Update
here is my array maainimg its not empty
maainimg = new int[]{R.drawable.ic_1_red,R.drawable.ic_2_red,R.drawable.ic_3_red,R.drawable.ic_4_red,R.drawable.ic_5_red,R.drawable.ic_6_red,
R.drawable.ic_7,R.drawable.ic_8,R.drawable.ic_8,R.drawable.ic_9,R.drawable.ic_10,R.drawable.ic_11,R.drawable.ic_12
,R.drawable.ic_13,R.drawable.ic_14,R.drawable.ic_15,R.drawable.ic_16,R.drawable.ic_17,R.drawable.ic_18,R.drawable.ic_19,R.drawable.ic_20,
R.drawable.ic_21,R.drawable.ic_22,R.drawable.ic_23,R.drawable.ic_24,R.drawable.ic_25};
While you call super(act, R.layout.custom_row); (without passing the objects), you need to override getCount() method, otherwise your adapter can't figure out how many items you have, and this is why there is no call of getView() method.
#Override
public int getCount(){
return img.length;
}
The first problem I see is your Layout.
<ListView
android:id="#+id/listvv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:divider="#b4be"
android:dividerHeight="2dp"></ListView>
<LinearLayout
android:id="#+id/ad_holder"
android:layout_width="fill_parent"
Your ListView has no room left because the bottom linear layout is using FILL_PARENT (which is deprecated btw, use MATCH_PARENT instead).
Try making your ListView height (and width) to be both MATCH_PARENT. And then deal with the "Ad".
You could have the LinearLayout replaced by a RelativeLayout and have the Ad pin at the bottom of its parent and below the listview.
Second: Why are you using an ArrayAdapter<String> if you're internally using an array of int.
Third: since you're using the wrong type of adapter, you're not correctly implementing it, you need to override more methods (getCount() for example), to tell the underlying adapter: hey, this is the number of items we have.
Since you're not using the provided array of strings, but your custom array of ints that you pass during construction, try overriding getCount() and return the size of your int array instead.
I this there is a issue in your Adapter class, Try this, But keep in mind that there are cleaner ways of writing this same code,
public class CustomAdapter extends ArrayAdapter<Integer> {
int[] img;
Context context;
ImageButton imageButton;
public CustomAdapter(Context context, Integer [] images) {
super(context, R.layout.custom_row, images);
this.context=context;
this.img=images;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.d("getView","Called!");
View row = convertView;
if(row==null){
LayoutInflater inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.custom_row, parent, false);
}
imageButton = (ImageButton) row.findViewById(R.id.preview);
imageButton.setImageResource(img[position]);
Log.d("added",position+"");
if (getSelectedcolor() == 0) {
imageButton.setColorFilter(Color.RED);
setSelectedcolor(Color.RED);
} else {
imageButton.setColorFilter(Color.parseColor(colorToHexString(getSelectedcolor())));
}
return row;
}
}

ListView add message from bottom to top?

I created a chat following this example: http://warting.se/2012/06/04/chat-bubbles-in-android/
works fine but I want when I add a new message the message displayed on bottom of ListView instead added on top, like whatsapp.
I did
<RelativeLayout 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/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="80dp"
android:divider="#android:color/transparent"
android:dividerHeight="0dp">
</ListView>
<RelativeLayout
android:id="#+id/form"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:orientation="vertical">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:ems="10"
android:id="#+id/chatText"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="#+id/buttonSend"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Enviar"
android:id="#+id/buttonSend"
android:layout_alignBottom="#+id/chatText"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:background="#color/action_bar"
android:textColor="#FFF"/>
</RelativeLayout>
ListAdapter
public class DiscussArrayAdapter extends ArrayAdapter<OneComment> {
private TextView countryName;
private List<OneComment> countries = new ArrayList<OneComment>();
private LinearLayout wrapper;
public DiscussArrayAdapter(Context context, int resource) {
super(context, resource);
}
#Override
public void add(OneComment object) {
countries.add(object);
super.add(object);
}
public int getCount() {
return this.countries.size();
}
public OneComment getItem(int index) {
return this.countries.get(index);
}
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.listitem_discuss, parent, false);
}
wrapper = (LinearLayout) row.findViewById(R.id.wrapper);
OneComment coment = getItem(position);
countryName = (TextView) row.findViewById(R.id.comment);
countryName.setText(coment.comment);
countryName.setBackgroundResource(coment.left ? R.drawable.bubble_yellow : R.drawable.bubble_green);
wrapper.setGravity(coment.left ? Gravity.LEFT : Gravity.RIGHT);
return row;
}
public Bitmap decodeToBitmap(byte[] decodedByte) {
return BitmapFactory.decodeByteArray(decodedByte, 0, decodedByte.length);
}
}
Instead of this:
countries.add(object);
super.add(object);
Use this:
countries.add(0,object);
super.insert(0,object);
The 0 indicates the position in the array, namely the beginning.
You have to add the object in the first position. Try this:
#Override
public void add(OneComment object) {
countries.add(0, object);
super.insert(0, object);
}
You call "add" from the ArrayList, and "insert" from the ArrayAdapter.
I hope it helps.
I encountered the same problem some times ago. I re ordered the List (in your case should be a List<OneComment>) before passing it to the Adapter.For Java order reference here.
<ListView
android:stackFromBottom="true"
...
></ListView>
Add this line in ListView.
Use a LinearLayout inside a ScrollView. Set height of ScrollView as MATCH_PARENT and set height of LinearLayout as WRAP_CONTENT. Set gravity of ScrollView to BOTTOM. Set orientation of LinearLayout to VERTICAL. Create another XML layout for your chat_message_item and inflate this layout while popping up new messages. Inflate and add new items in LinearLayout as mLinearLayout.addView(chatMessageItem).
This will work.

Listview create all elements instead of visible ones

I have an issue which I didn't found any solutions on stackoverflow (or anywhere else so far).
Summary :
I have scrollview and inside of it a ListView with visibility gone (Can switch with a TextView).
When I set the adapter content, in my activity the onScroll get call with 4 visibles Item but the getView of the adapter get call for the whole dataSet (181 items) which bring a lot of performance issues / imageref_ashmem create failed ... (Of course remove image loading remove fail of creation but well :D)
=== Activity ===
Result of Activity in onScroll
firstVisibleItem 0
visibleItemCount 4
totalItemCount 181
=== Layout extract ===
<ScrollView
android:id="#+id/UserProfileView_ScrollView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:fillViewport="true"
android:background="#00FFFFFF" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#00FFFFFF" >
<RelativeLayout
android:id="#+moreDetails/UserProfileView_BottomLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_below="#+profile/UserProfileView_MoreDetails"
android:background="#FFFFFFFF" >
<TextView
android:id="#+id/UserProfileView_About"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#ff111111"
android:visibility="gone" />
<ListView
android:id="#+id/UserProfileView_MoreDetails_ListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:footerDividersEnabled="false"
android:divider="#color/unactivatedLightGray"
android:dividerHeight="1dp"
android:listSelector="#android:color/transparent"
android:visibility="gone" />
</RelativeLayout>
</RelativeLayout>
</ScrollView>
The height of the BottomLayout is set to 3/4 of the width of the screen programmatically.
=== Adapter ===
public class CommonAdapter extends BaseAdapter {
public List<Common> list;
private LayoutInflater inflater;
private AQuery aq;
public CommonAdapter(Context context, List<Common> list) {
this.inflater = LayoutInflater.from(context);
this.list = list;
this.aq = new AQuery(context);
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int position) {
return list.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
private class ViewHolder {
ImageView thumbImg;
TextView name;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.list_view_item, null);
holder.thumbImg = (ImageView) convertView.findViewById(R.id.CommonCell_Thumb);
holder.name = (TextView) convertView.findViewById(R.id.CommonCell_Name);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Common obj = list.get(position);
if (list.get(position).getPicture() != null)
aq.id(holder.thumbImg).image(obj.getPicture());
else
aq.id(holder.thumbImg).image(Util.Thumb(list.get(position).getId()), options);
holder.name.setText(obj.getName());
return convertView;
}
}
EDIT : Every time I scroll, the whole dataset it parse again, so 181 call to getView.
I assume your aq.id(stuff) loads an image asyncronous.
If so, check your layout/list_view_item.xml it's height is probably set to wrap_content and the ImageView also has no fixed height. Meaning while loading the image this row has a zero or very small height. Therefore all 182 rows fit into the ListView at once and getView() gets called for every single one.
Set a fixed height or minHeight for every row or the ImageView the ListView will only call getView() for as many rows fit into the ListView.
Hope this helps
I fixed the issue by set the ListView to an arbitrary Height.
<ListView
android:id="#+id/UserProfileView_MoreDetails_ListView"
android:layout_width="match_parent"
android:layout_height="1080dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:footerDividersEnabled="false"
android:divider="#color/unactivatedLightGray"
android:dividerHeight="1dp"
android:listSelector="#android:color/transparent"
android:visibility="gone" />
If ListView or RecyclerView used in ScrollView, All items will initiate at the same time.

Android: button showing up multiple times in list view

I trying to write code to highlight the selected value of the list with "Next" button at the bottom of the layout. But for some reason, after every list item, "next" button also shows up. Can someone please help me resolve this problem?
Here is the layout file:
<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:orientation="vertical"
android:id="#+id/questionLayout"
>
<TextView android:id="#+id/txtExample"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="25sp"
android:textColor="#000000"
android:background="#FF0000"
/>
<ListView
android:id="#+id/listExample"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#CCCCCC"
android:choiceMode="singleChoice"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<Button
android:id = "#+id/next"
android:text="Next"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_gravity="center"
android:layout_weight="50"
/>
<Button
android:id = "#+id/submit"
android:text="Submit"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:layout_weight="50"
android:layout_gravity="center"
/>
</LinearLayout>
</LinearLayout>
Java Code:
public class updateList extends Activity {
private SelectedAdapter selectedAdapter;
private ArrayList<String> list;
int correct_answer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list = new ArrayList<String>();
list.add("Choice One");
list.add("Choice Two");
list.add("Choice Three");
selectedAdapter = new SelectedAdapter(this,0,list);
selectedAdapter.setNotifyOnChange(true);
ListView listview = (ListView) findViewById(R.id.listExample);
listview.setAdapter(selectedAdapter);
listview.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View view,
int position, long id) {
// user clicked a list item, make it "selected"
selectedAdapter.setSelectedPosition(position);
}
});
}
}
Thanks in advance
SSP
Selected Adaptor class:
public class SelectedAdapter extends ArrayAdapter{
// used to keep selected position in ListView
private int selectedPos = -1; // init value for not-selected
public SelectedAdapter(Context context, int textViewResourceId,
List objects) {
super(context, textViewResourceId, objects);
}
public void setSelectedPosition(int pos){
selectedPos = pos;
// inform the view of this change
notifyDataSetChanged();
}
public int getSelectedPosition(){
return selectedPos;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
// only inflate the view if it's null
if (v == null) {
LayoutInflater vi = (LayoutInflater)this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.activity_main, null);
}
// get text view
TextView label = (TextView)v.findViewById(R.id.txtExample);
// change the row color based on selected state
if(selectedPos == position){
label.setBackgroundColor(Color.CYAN);
}else{
label.setBackgroundColor(Color.WHITE);
}
label.setText(this.getItem(position).toString());
/*
// to use something other than .toString()
MyClass myobj = (MyClass)this.getItem(position);
label.setText(myobj.myReturnsString());
*/
return(v);
}
}
change your listview in xml as like this
<ListView
android:id="#+id/listExample"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"//===== set maximum heighthere
android:layout_marginBottom="50dp"// === give some space at bottom so that buttons will appear
android:background="#CCCCCC"
android:choiceMode="singleChoice"
/>
But for some reason, after every list item, "next" button also shows up.
The ListView's row layout is determined by the layout you inflate in getView() or pass to your Adapter's super class if you haven't overridden getView(). Double check this layout and remove the unwanted code.
Addition
The layout for your ListView's items only needs to be one TextView since you only want to display a phrase in each. However you are currently passing your entire main layout, this creates the Buttons, an unused ListView, and everthing else in every row...
Instead use android.R.layout.simple_list_item_1 in getView(), of course you'll need to change the id you pass to findViewById() as well:
if (v == null) {
LayoutInflater vi = (LayoutInflater)this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(android.R.layout.simple_list_item_1, null);
}
// get text view
TextView label = (TextView)v.findViewById(android.R.id.text1);
Please watch Android's Romain Guy discuss writing an efficient adapter to speed things up.

Why do I need to call removeView() in order to add a View to my LinearLayout

I am getting this error but I am not sure exactly why:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
The part where I add the View is the line that the error is pointing to. I am providing my Adapter code in order for you guys to get a better picture of what I am doing and why I am getting this error. Please let me know if anymore info is needed. Thanks in advance.
Adapter
private class InnerAdapter extends BaseAdapter{
String[] array = new String[] {"12\nAM","1\nAM", "2\nAM", "3\nAM", "4\nAM", "5\nAM",
"6\nAM", "7\nAM", "8\nAM", "9\nAM", "10\nAM", "11\nAM",
"12\nPM", "1\nPM", "2\nPM", "3\nPM", "4\nPM", "5\nPM",
"6\nPM", "7\nPM", "8\nPM", "9\nPM", "10\nPM", "11\nPM"};
TextView[] views = new TextView[24];
public InnerAdapter() {
TextView create = new TextView(DayViewActivity.this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 62, getResources().getDisplayMetrics()), 1.0f);
params.topMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
params.bottomMargin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
create.setLayoutParams(params);
create.setBackgroundColor(Color.BLUE);
create.setText("Test");
views[0] = create;
for(int i = 1; i < views.length; i++) {
views[i] = null;
}
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return array.length;
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#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]);
LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.day_event_layout);
if(views[position] != null) {
layout.addView((TextView)views[position], position);
}
return convertView;
}
}
XML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="61dp"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="61dp"
android:orientation="vertical">
<TextView
android:id="#+id/day_hour_side"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:text="12AM"
android:background="#bebebe"
android:layout_weight="0"
android:textSize="10dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_weight="0"
android:background="#000000"
android:id="#+id/hour_side_divider"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="61dp"
android:orientation="vertical"
android:layout_weight="1">
<LinearLayout
android:id="#+id/day_event_layout"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal" ></LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#000000"
android:id="#+id/event_side_divider" />
</LinearLayout>
</LinearLayout>
You didn't say when you get that exception(when the application starts or when you scroll the GridView up and down) but it's normal. The views array has one value that is not null(the first entry in that array in set to the TextView that you create) and most likely you'll be trying to re-add that TextView at some point. Also the parent AdapterView may call the getView method several times to get some children to measure.
Anyway you don't know exactly what you're trying to do but the current approach is wrong.
First, you create an array with one TextView and the rest of the values set to null and you basically don't do anything else with it(but maybe this isn't the full code?!). Second, you shouldn't store an array of Views especially within a child of AdapterView(like GridView, ListView etc) which has a mechanism to recycle its children. Third, you didn't take in consideration the recycling mechanism of the GridView. For example, you add the TextView for the first element but you don't revert this changes in the getView so if this first row's View(which contains the added TextView) gets recycled you'll end up with a row View containing the previously added TextView at rows where you don't want it.
I already accepted an answer, but thought I'd add this as it helps explain some stuff about ListView (and by definition, GridView as well), that someone learning about it can understand. I was confused about recycling Views in ListView, and this article I found is great. Explains it well. Hopefully it helps anyone not fully understanding how ListView and Adapters work, which was an obvious problem for me.

Categories

Resources