The gridview items change order randomly sometimes when i click on items and mostly when scrolling. I have searched all over the internet but couldn't find a solution which works for recyclerview.
This is my layout adapter class
public class LayoutAdapter extends RecyclerView.Adapter<LayoutAdapter.SimpleViewHolder>{
private static final int COUNT = 100;
private static final String TAG = "LayoutAdapter";
private final Context mContext;
private final TwoWayView mRecyclerView;
private final int mLayoutId;
private int mCurrentItemId = 0;
private FileManager file_manager;
private ArrayList<Integer> positions;
private static LayoutInflater inflator = null;
private TextView folder_name;
private Context c;
ArrayList<String> mDataSource, mMultiSelectData;
private File file, files;
private File[] list2;
public boolean multi_select_flag = false;
public class SimpleViewHolder extends RecyclerView.ViewHolder {
public SimpleViewHolder(View view) {
super(view);
thumbnail = (ImageView) view.findViewById(R.id.ivFolderThumbnail);
folder_name = (TextView) view.findViewById(R.id.tvFolderTitle);
}
}
//In logcat I see this constructor is being called again and again and again!
public LayoutAdapter(Context context, TwoWayView recyclerView, int layoutId, FileManager filemanager, String file_path) {
mContext = context;
file_manager = filemanager;
c = context;
mDataSource = new ArrayList<String>(file_manager.setHomeDir
(Environment.getExternalStorageDirectory().getPath()));
mRecyclerView = recyclerView;
mLayoutId = layoutId;
String root_sd = Environment.getExternalStorageDirectory().toString();
if (file_path == null) {
file = new File(root_sd);
} else {
file = new File(root_sd + "/" + file_path);
}
Log.d(TAG, "GOT ALL FILES >>>>>>" + root_sd);
list2 = file.listFiles();
}
public String getName(int position) {
String name = list2[position].getName();
return name;
}
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(mContext).inflate(R.layout.grid_item, parent, false);
return new SimpleViewHolder(view);
}
public String getData(int position) {
if (position > mDataSource.size() - 1 || position < 0)
return null;
return mDataSource.get(position);
}
#Override
public void onBindViewHolder(SimpleViewHolder holder, int position) {
// boolean isVertical = (mRecyclerView.getOrientation() ==TwoWayLayoutManager.Orientation.VERTICAL);
final View itemView = holder.itemView;
int num_items = 0;
String temp = file_manager.getCurrentDir();
File file = new File(temp + "/" + mDataSource.get(position));
String[] list = file.list();
if (list != null)
num_items = list.length;
Log.d(TAG, ">>>>>>>>>>>>> " + String.valueOf(file.length()));
folder_name.setText(file.getName());
}
}
#Override
public int getItemCount() {
return mDataSource.size();
}
}
This is the layout file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="105dp"
android:layout_height="105dp"
android:orientation="vertical" >
<com.filemanager.android.SquareImageView
android:id="#+id/ivFolderThumbnail"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginLeft="15dp"
android:scaleType="centerCrop"
android:src="#drawable/ic_launcher" />
<TextView
android:id="#+id/tvFolderTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/ivFolderThumbnail"
android:text="Medium Text"
android:textColor="#android:color/black"
android:textAppearance="?android:attr/textAppearanceMedium" />
<ImageView
android:id="#+id/ivMultiSelect"
android:layout_width="50dp "
android:layout_height="50dp"
android:layout_above="#+id/tvFolderTitle"
android:layout_toRightOf="#+id/ivFolderThumbnail"
android:src="#drawable/ic_action_new" />
</RelativeLayout>
Could you please post the layout definitions as well? We already know that if the items do not have fixed or pre-defined dimensions, then the items may shift order in case of TwoWay/Recycler Views.
This happens because in recycler view older item views are reused when we scroll down and older item dimensions may differ from the new item dimensions. Hence they may reorder.
In that case setting fixed dimensions for your ImageView and TextView would solve the issue or determine the dimension of the ImageView before inflating.
I ran in the same problem, which is/was really annoying. I tested several things and one of them did the trick: I dont know why but you have to set the item animator explicitly to null for the recycler view with [RecyclerView].setItemAnimator(null); ... Especially the first items reordered when scrolling up again in my staggered layout. Now it is gone. Hope this helps you as well.
Issue # GitHub
Yes, it is very annoying; the solution which I have realized is in adapter just clear all the conditions like for every if condition there will also be else with valid body.
Try this approach you will get rid of this issue.
Related
I am trying to filter a custom List View with a custom Adapter. I am having problems with duplicating the original Data and putting it back in the list, when the search parameter changes or goes to empty. The filtering does work for the first input character, but if this is changed, it won't search the whole dataset again. I know that this is because I need a duplicate list of the original data but I can't really get it to work, because I don't know how to properly implement it because I am using a custom Class as my Datatype. I only use the name and category property of it though, the names are the actual items and it is also sorted by categories.
I based my Adapter off of this example: https://gist.github.com/fjfish/3024308
And here is my code for the List Adapter:
class DataListAdapter extends BaseAdapter implements Filterable {
private Context mContext;
private List<Object> originalData = null;
private List<Object> filteredData = null;
private static final int CARRIER = 0;
private static final int HEADER = 1;
private LayoutInflater inflater;
private ItemFilter mFilter = new ItemFilter();
DataListAdapter(Context context, List<Object> input) {
this.mContext = context;
this.originalData = input;
this.filteredData = input;
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getItemViewType(int position) {
if (originalData.get(position) instanceof Carrier) {
return CARRIER;
} else {
return HEADER;
}
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getCount() {
return originalData.size();
}
#Override
public Object getItem(int position) {
return originalData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#SuppressLint("InflateParams")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
switch (getItemViewType(position)) {
case CARRIER:
convertView = inflater.inflate(R.layout.listview_item_data_layout, null);
break;
case HEADER:
convertView = inflater.inflate(R.layout.listview_header_data_layout, null);
break;
}
}
switch (getItemViewType(position)) {
case CARRIER:
TextView name = (TextView) convertView.findViewById(R.id.fragment_data_list_view_carrier_name);
name.setText(((Carrier) originalData.get(position)).get_name());
break;
case HEADER:
TextView category = (TextView) convertView.findViewById(R.id.fragment_data_list_view_category);
category.setText((String) originalData.get(position));
break;
}
return convertView;
}
#Override
public Filter getFilter() {
return mFilter;
}
private class ItemFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
DatabaseHelper dbHelper = new DatabaseHelper(mContext, null, null, 1);
String filterString = constraint.toString().toLowerCase();
FilterResults results = new FilterResults();
final List<Object> list = originalData;
int count = list.size();
final List<Object> nlist = new ArrayList<>(count);
String filterableString = "";
for (int i = 0; i < count; i++) {
switch (getItemViewType(i)) {
case CARRIER:
filterableString = ((Carrier)list.get(i)).get_name();
break;
case HEADER:
filterableString = "";
break;
}
if(filterableString.toLowerCase().contains(filterString)) {
nlist.add(dbHelper.getCarriersWithName(filterableString).get(0));
}
}
results.values = nlist;
results.count = nlist.size();
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if(results.count == 0) {
notifyDataSetInvalidated();
} else {
originalData = (List<Object>)results.values;
notifyDataSetChanged();
}
}
}
}
My main activity obviously looks like this, which should be fine. The problem lays in the filtered Data List, which I can't get to work.
List<Object> combinedCategoryCarrierList = dbHelper.getCombinedCategoryCarrierList();
adapter = new DataListAdapter(mContext, combinedCategoryCarrierList);
listView.setAdapter(adapter);
listView.setTextFilterEnabled(true);
searchEditText = (EditText) view.findViewById(R.id.fragment_data_search);
searchEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
adapter.getFilter().filter(searchEditText.getText().toString());
}
});
I would greatly appreciate it if someone can show me an example of how to do that with custom data types and section headers combined. Or even change my code :) I can't really find examples where all of that applies.
Edit: The screen looks like this, so I want to keep the category headers when filtering.
I did not find a solution to my original problem, but I came up with a better approach to the whole situation. I didn't know there was an ExpandableListView available in Android. This is basically a ListView, but the items are divided into Groups and their Childs which are expandable and collapsable, so exactly what I wanted.
Here is how I implemented it with working filters and groups:
So, to start off, here is my main layout file. Please note that I am using Fragments, which is why the code is a bit different in terms of getting the context for example. The functionality of the component stays the same though.
<?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" >
<EditText
android:id="#+id/fragment_data_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:hint="#string/data_search_hint"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp" />
<ExpandableListView
android:id="#+id/fragment_data_expandable_list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:groupIndicator="#null" />
</LinearLayout>
You will also need two layout files for your header/group items and for your child items. My header item has a TextView which displays the category name and an ImageView which displays a + or - to show if the category is collapsed or expanded.
Here is my header layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorAccent"
android:descendantFocusability="blocksDescendants" >
<TextView
android:id="#+id/fragment_data_list_view_category"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:gravity="start"
android:textStyle="bold"
android:textSize="18sp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:textColor="#android:color/primary_text_light"
android:text="#string/placeholder_header_listview"
android:maxLines="1"
android:ellipsize="end" />
<ImageView
android:id="#+id/fragment_data_list_view_category_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_gravity="end"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:contentDescription="#string/content_description_list_view_header"
android:src="#drawable/ic_remove_black_24dp"
android:tag="maximized"/>
</RelativeLayout>
The property android:descendantFocusability="blocksDescendants" fixed a bug when I tried setting an onItemClickListener. If you have that problem, try using RelativeLayout's for your child layout if you're not already. It fixed it for me, the onClickItemListener did not execute with a LinearLayout.
And here is my layout file for the child items:
<?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="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:descendantFocusability="blocksDescendants" >
<TextView
android:id="#+id/fragment_data_list_view_carrier_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/placeholder_item_listview"
android:textSize="18sp"
android:textStyle="normal"
android:textColor="#android:color/primary_text_light"
android:maxLines="1"
android:ellipsize="end" />
</RelativeLayout>
The following code is from my fragment class, which handles all the logic for the ExpandableListView:
public class Fragment_Data extends Fragment {
private Context mContext;
private ExpandableListView expandableListView;
private List<String> categories_list;
private HashMap<String, List<Carrier>> carriers_list;
private DataExpandableListAdapter adapter;
private DatabaseHelper dbHelper;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getActivity().setTitle(R.string.nav_item_data);
}
This first part shows the declaration of needed variables and the necessary method onViewCreated. The Carrier class is a custom object with properties like name, category and so on. The DatabaseHelper is also a custom class which handley my database and gets all the data for me, which is casted into Carrier objects. You can of course use anything you like as data types.
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_data_layout, container, false);
mContext = getContext();
expandableListView = (ExpandableListView) view.findViewById(R.id.fragment_data_expandable_list_view);
dbHelper = new DatabaseHelper(mContext, null, null, 1);
adapter = new DataExpandableListAdapter(mContext, categories_list, carriers_list);
displayList();
expandAllGroups();
EditText searchEditText = (EditText) view.findViewById(R.id.fragment_data_search);
searchEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
adapter.filterData(s.toString());
expandAllGroups();
}
#Override
public void afterTextChanged(Editable s) {
}
});
expandableListView.setOnItemLongClickListener(deleteSelectedItem);
expandableListView.setOnChildClickListener(editSelectedItem);
return view;
}
The onCreate method deals with all the important stuff like setting the adapter, inflating the layout and setting onClick events for the items and a onTextChange event for the search field.
private void expandAllGroups() {
for(int i = 0; i < adapter.getGroupCount(); i++) {
expandableListView.expandGroup(i);
}
}
private void displayList() {
prepareListData();
adapter = new DataExpandableListAdapter(mContext, categories_list, carriers_list);
expandableListView.setAdapter(adapter);
expandAllGroups();
}
private void prepareListData() {
categories_list = new ArrayList<>();
carriers_list = new HashMap<>();
categories_list = dbHelper.getCategoryList();
for(int i = 0; i < categories_list.size(); i++) {
List<Carrier> carrierList = dbHelper.getCarriersWithCategory(categories_list.get(i));
carriers_list.put(categories_list.get(i), carrierList);
}
}
With expandAllGroups() you can simply expand all groups, because they are collapsed by default. The displayList() simply sets the Adapter for the ExpandableListView and calls prepareListData(), which fills both the category (group) list and the carrier (child) list. Note that the child List is a hashmap with the key being the category and the value a Carrier List by itself, so the Adapter knows which child items belong to which parent.
Here is the code for the Adapter:
class DataExpandableListAdapter extends BaseExpandableListAdapter {
private Context mContext;
private List<String> list_categories = new ArrayList<>();
private List<String> list_categories_original = new ArrayList<>();
private HashMap<String, List<Carrier>> list_carriers = new HashMap<>();
private HashMap<String, List<Carrier>> list_carriers_original = new HashMap<>();
DataExpandableListAdapter(Context context, List<String> categories, HashMap<String, List<Carrier>> carriers) {
this.mContext = context;
this.list_categories = categories;
this.list_categories_original = categories;
this.list_carriers = carriers;
this.list_carriers_original = carriers;
}
You need to have a copy of both of your original lists, if you want to use filtering. This is used for restoring all data when the search query is empty or again or simply different. The filter deletes all items that do not match from the original list.
#Override
public int getGroupCount() {
return this.list_categories.size();
}
#Override
public int getChildrenCount(int groupPosition) {
return this.list_carriers.get(this.list_categories.get(groupPosition)).size();
}
#Override
public Object getGroup(int groupPosition) {
return this.list_categories.get(groupPosition);
}
#Override
public Object getChild(int groupPosition, int childPosition) {
return this.list_carriers.get(this.list_categories.get(groupPosition)).get(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 boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
Those methods need to be overwritten when you expand the BaseExpandableListAdapter. You can replace all the return null; statements with something similar like this, depending on your data.
#SuppressLint("InflateParams")
#Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
String headerTitle = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.listview_header_data_layout, null);
}
TextView lblListHeader = (TextView) convertView.findViewById(R.id.fragment_data_list_view_category);
lblListHeader.setText(headerTitle);
ImageView expandIcon = (ImageView) convertView.findViewById(R.id.fragment_data_list_view_category_icon);
if(isExpanded) {
expandIcon.setImageResource(R.drawable.ic_remove_black_24dp);
} else {
expandIcon.setImageResource(R.drawable.ic_add_black_24dp);
}
return convertView;
}
This overriden method simply inflates the layout for each header/group/category item and sets it text and image depending on the state of the group, if it's collapsed or expanded.
#SuppressLint("InflateParams")
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
final String carrierName = ((Carrier)getChild(groupPosition, childPosition)).get_name();
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.listview_item_data_layout, null);
}
TextView txtListChild = (TextView) convertView.findViewById(R.id.fragment_data_list_view_carrier_name);
txtListChild.setText(carrierName);
return convertView;
}
Same thing with the child items.
Now finally to the filtering:
I use this custom method to filter out all items that I need matching the search query. Remember that this method is called each time the text of the EditText changes.
void filterData(String query) {
query = query.toLowerCase();
list_categories = new ArrayList<>();
list_carriers = new HashMap<>();
DatabaseHelper dbHelper = new DatabaseHelper(mContext, null, null, 1);
if(query.trim().isEmpty()) {
list_categories = new ArrayList<>(list_categories_original);
list_carriers = new HashMap<>(list_carriers_original);
notifyDataSetInvalidated();
}
else {
//Filter all data with the given search query. Yes, it's complicated
List<String> new_categories_list = new ArrayList<>();
HashMap<String, List<Carrier>> new_carriers_list = new HashMap<>();
List<String> all_categories_list = dbHelper.getCategoryList();
for(int i = 0; i < all_categories_list.size(); i++) {
List<Carrier> carriersWithCategoryList = dbHelper.getCarriersWithCategory(all_categories_list.get(i));
List<Carrier> matchingCarriersInCategory = new ArrayList<>();
for(Carrier carrierInCategory : carriersWithCategoryList) {
if(carrierInCategory.get_name().toLowerCase().contains(query)) {
matchingCarriersInCategory.add(carrierInCategory);
if(!new_categories_list.contains(all_categories_list.get(i))) {
new_categories_list.add(all_categories_list.get(i));
}
}
}
new_carriers_list.put(all_categories_list.get(i), matchingCarriersInCategory);
}
if(new_categories_list.size() > 0 && new_carriers_list.size() > 0) {
list_categories.clear();
list_categories.addAll(new_categories_list);
list_carriers.clear();
list_carriers.putAll(new_carriers_list);
}
notifyDataSetChanged();
}
}`
This might be very confusing, but it needs to be that complicated in my case because of my data structure. It might be easier in your case.
What this basically does is, that it first checks if the search query is empty. And if it is empty it resets both lists to the "backup" lists which I assigned in the constructor. I then call notifyDataSetInvalidated(); to tell the Adapter that it's content will be refilled. It might work aswell with notifyDataSetChanged();, I didn't test that, but it should since we set the original lists back to their old state.
Now, if the search query is not empty I go through every category and see if that specific category has any items that match the search query. If that is the case, that item is added to a new child list and it's category/parent will also be added to a new parent list, if it's not already in there.
And last but not least, the method checks if both lists are not empty. If they are not empty, the original lists are emptied and the new, filtered data, is put in and the Adapter is notified by calling notifyDataSetChanged();
I hope this will help anyone.
For my Android project, I have a listview which has a checkbox for every item. The data is loaded from an SQLite database by using a CursorAdapter class. However, whenever I scroll, the checkbox positions will get moved and get carried down to the next part of the listview. How can I fix this problem?
GIF of my CheckBox Problem
Here's my Cursor Adapter Class:
public class VocabCursorAdapter extends CursorAdapter {
private static final int DIFFICULT = 0;
private static final int FAMILIAR = 1;
private static final int EASY = 2;
private static final int PERFECT = 3;
public VocabCursorAdapter(Context context, Cursor c, int flags) {
super(context, c, 0);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.item_vocab, parent, false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// Find fields to populate in inflated template
TextView tvVocabName = (TextView) view.findViewById(R.id.vocabName);
TextView tvVocabDefinition = (TextView) view.findViewById(R.id.vocabDefinition);
ImageView tvVocabLevel = (ImageView) view.findViewById(R.id.vocabLevel);
// Extract properties from cursor
String vocab = cursor.getString(cursor.getColumnIndexOrThrow(VocabDbContract.COLUMN_NAME_VOCAB));
String definition = cursor.getString(cursor.getColumnIndexOrThrow(VocabDbContract.COLUMN_NAME_DEFINITION));
int level = cursor.getInt(cursor.getColumnIndexOrThrow(VocabDbContract.COLUMN_NAME_LEVEL));
// Populate fields with extracted properties
tvVocabName.setText(vocab);
tvVocabDefinition.setText(definition);
if (level == DIFFICULT) {
tvVocabLevel.setImageResource(R.drawable.level_bars_difficult);
tvVocabLevel.setTag(DIFFICULT);
}
else if (level == FAMILIAR) {
tvVocabLevel.setImageResource(R.drawable.level_bars_familiar);
tvVocabLevel.setTag(FAMILIAR);
}
else if (level == EASY) {
tvVocabLevel.setImageResource(R.drawable.level_bars_easy);
tvVocabLevel.setTag(EASY);
}
else if (level == PERFECT) {
tvVocabLevel.setImageResource(R.drawable.level_bars_perfect);
tvVocabLevel.setTag(PERFECT);
}
}
And here's my list item xml, item_vocab.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:longClickable="true">
<ImageView
android:layout_width="36sp"
android:layout_height="36sp"
android:id="#+id/vocabLevel"
android:layout_gravity="right"
android:src="#drawable/level_bars"
android:scaleType="fitXY"
android:contentDescription="#string/vocab_level"
android:layout_centerVertical="true"
android:layout_toLeftOf="#+id/editCheckbox"
android:layout_toStartOf="#+id/editCheckbox"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/vocabName"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="#+id/vocabLevel"
android:layout_toStartOf="#+id/vocabLevel"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/vocabDefinition"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="#+id/vocabLevel"
android:layout_toStartOf="#+id/vocabLevel"
android:layout_below="#id/vocabName"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/editCheckbox"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
</RelativeLayout>
And here's my xml which contains a listview
<RelativeLayout 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"
tools:context=".controller.MyVocab"
android:paddingLeft="5dp">
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/mVocabList"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/empty_text_view"
android:id="#android:id/empty"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
</RelativeLayout>
I have looked at a lot of different solutions on StackOverflow, but I wasn't able to successfully do it in my own app. For an example, this post has a similar problem, but its solution used getView and I had trouble understanding how to implement it with newView and bindView instead.
And some other solutions might be examples where a cursoradapter is not involved. Any help is much appreciated, thanks a lot!
Edit #1: After incorporating Phan's changes, the checkbox states get resets to false rather than keeping its states when I scroll the listview (See ).
Reason : ListView re-uses the views.
Solution :
class VocabCursorAdapter extends CursorAdapter {
List<Integer> selectedItemsPositions;//to store all selected items position
public VocabCursorAdapter(Context context, Cursor c,int flags) {
super(context, c,0);
selectedItemsPositions = new ArrayList<>();
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
View view = LayoutInflater.from(context).inflate(R.layout.item_vocab, viewGroup, false);
CheckBox box = (CheckBox) view.findViewById(R.id.editCheckbox);
box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
int position = (int) compoundButton.getTag();
if (b) {
//check whether its already selected or not
if (!selectedItemsPositions.contains(position))
selectedItemsPositions.add(position);
} else {
//remove position if unchecked checked item
selectedItemsPositions.remove((Object) position);
}
}
});
return view;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
//your other stuff
CheckBox box = (CheckBox) view.findViewById(R.id.editCheckbox);
box.setTag(cursor.getPosition());
if (selectedItemsPositions.contains(cursor.getPosition()))
box.setChecked(true);
else
box.setChecked(false);
}
}
Try this
public class VocabCursorAdapter extends CursorAdapter {
private ArrayList<Boolean> itemChecked = new ArrayList<Boolean>(); // array list for store state of each checkbox
public VocabCursorAdapter(Context context, Cursor c, int flags) {
for (int i = 0; i < c.getCount(); i++) { // c.getCount() return total number of your Cursor
itemChecked.add(i, false); // initializes all items value with false
}
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
...
final int position = cursor.getPosition(); // get position by cursor
CheckBox checkBox = (CheckBox) view.findViewById(R.id.editCheckbox);
checkBox.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (itemChecked.get(position) == true) { // if current checkbox is checked, when you click -> change it to false
itemChecked.set(position, false);
} else {
itemChecked.set(position, true);
}
}
});
checkBox.setChecked(itemChecked.get(position)); // set the checkbox state base on arraylist object state
Log.i("In VocabCursorAdapter","position: "+position+" - checkbox state: "+itemChecked.get(position));
}
}
public class ObservationselectattributeFragment extends Fragment {
DatabaseHandler mDBHandler;
ListView mListView;
SimpleCursorAdapter mSCA;
Cursor mCsr;
ArrayList<String> attributeItems = new ArrayList<>();
public ObservationselectattributeFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate the layout for this fragment
View view1=inflater.inflate(R.layout.fragment_observationselectattribute, container, false);
//Bundle bundle2 = getArguments();
Bundle bundle1 = getArguments();
final int firsttext= bundle1.getInt("TotalCount");
final String selectedtreatment= bundle1.getString("SelectedTreatment");
Toast.makeText(getActivity(),"value \n"+firsttext+"\n"+"treatment \n"+selectedtreatment, Toast.LENGTH_SHORT).show();
// Toast.makeText(getActivity(),"SelectedTreatment \n"+selectedtreatment, Toast.LENGTH_SHORT).show();
mListView = (ListView)view1.findViewById(R.id.lv001);
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
Button addattribute = (Button)view1.findViewById(R.id.addattribute);
addattribute.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String items1="";
Integer tcount1=0;
for(String item1:attributeItems){
items1+="-"+item1+"\n";
tcount1++;
}
Toast.makeText(getActivity(),"you have selected \n"+items1,Toast.LENGTH_LONG).show();
Toast.makeText(getActivity(),"you have selected \n"+tcount1,Toast.LENGTH_LONG).show();
/*FragmentTransaction fr= getFragmentManager().beginTransaction();
fr.replace(R.id.main_container, new ShowObservationDataRecordingFragment()).addToBackStack("ObservationselectattributeFragment");
fr.commit();*/
Bundle bundle = new Bundle();
bundle.putInt("TotalCount2",firsttext);
bundle.putInt("TotalCount1", tcount1);
bundle.putString("SelectedTreatment", selectedtreatment);
Fragment showobservationdatarecordingfragment = new ShowObservationDataRecordingFragment();
showobservationdatarecordingfragment.setArguments(bundle);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.main_container, showobservationdatarecordingfragment).addToBackStack("ObservationselectattributeFragment").commit();
}
});
mDBHandler = new DatabaseHandler(this.getActivity());
mCsr = mDBHandler.getAllRecords();
// Prepare a list of the columns to get the data from, for the ListViewt
String[] columns_to_get_data_from = new String[]{
DatabaseHandler.KEY_IDS,
DatabaseHandler.KEY_NAMES,
DatabaseHandler.KEY_FNAME,
DatabaseHandler.KEY_MONAME,
DatabaseHandler.KEY_SNAME
};
// Prepare a list of the Views into which to place the data
int[] itemviews_to_place_data_in = new int[]{
R.id.euserid,
R.id.eusername,
R.id.efname,
R.id.emoname,
R.id.esname
};
// get and instance of SimpleCursorAdapter
mSCA = new SimpleCursorAdapter(getActivity(),
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
0);
// Save the ListView state (= includes scroll position) as a Parceble
Parcelable state = mListView.onSaveInstanceState();
// get and instance of SimpleCursorAdapter the listviewitem_record layout
mListView.setAdapter(mSCA);
// Restore previous state (including selected item index and scroll position)
mListView.onRestoreInstanceState(state);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String attributeItem1 = ((TextView)view.findViewById(R.id.euserid)).getText().toString();
String attributeItem2 = ((TextView)view.findViewById(R.id.eusername)).getText().toString();
String attributeItem3 = ((TextView)view.findViewById(R.id.efname)).getText().toString();
String attributeItem4 = ((TextView)view.findViewById(R.id.emoname)).getText().toString();
String attributeItem5 = ((TextView)view.findViewById(R.id.esname)).getText().toString();
String attributeItem = attributeItem1 + attributeItem2 + attributeItem3 + attributeItem4 + attributeItem5;
// CheckedTextView box = (CheckedTextView) view.findViewById(R.id.record_checkbox);
// box.setChecked(true);
CheckedTextView checkedTextView = (CheckedTextView) view.findViewById(R.id.record_checkbox);
if(checkedTextView.isChecked()) {
checkedTextView.setChecked(false);
} else {
checkedTextView.setChecked(true);
}
if(attributeItems.contains(attributeItem)){
attributeItems.remove(attributeItem);//uncheck item
}
else
{
attributeItems.add(attributeItem);
}
Toast.makeText(getActivity(), "Item1 = " + attributeItem1 +"\n"+ "Item2 ="+attributeItem2 +"\n"+"Item3 ="+attributeItem3+"\n"+"Item4 ="+attributeItem4+"\n"+"Item5 ="+attributeItem5, Toast.LENGTH_SHORT).show();
}
});
((HomeActivity) getActivity())
.setActionBarTitle("Select Attribute");
return view1;
}
}
I get rows from a db as an ArrayList. I want to use data that is in two of the columns to populate a list view.
What I have done so far only shows the ?row reference? (com.app.Poster#2349049)
ListView listView = (ListView) findViewById(R.id.poster_list_view);
MySQLiteHelper db = new MySQLiteHelper(this);
List<Poster> posters = db.getAllPosters();
ArrayAdapter<Poster> listAdapter = new ArrayAdapter<Poster>(this, android.R.layout.simple_list_item_1, posters);
listView.setAdapter(listAdapter);
I thought maybe I am suppose to loop the ArrayList and add each row to the adapter
for (Poster p : posters){
listAdapter.add(p.getPosterTitle());
}
Apparently the adapter only wants an object I think. Should I be customizing an adapter for this? I thought it would be a lot easier.
This is my Poster Class
public class Poster {
private int posterId;
private int categoryId;
private int eventId;
private String presenterFname;
private String presenterLname;
private String posterTitle;
private String posterSynopsis;
private String posterFilename;
private String posterRemoteLocation;
public Poster(int pid, int cid, int eid, String prf, String prl, String pt, String ps, String pfn, String fl){
posterId = pid;
categoryId = cid;
eventId = eid;
presenterFname = prf;
presenterLname = prl;
posterTitle = pt;
posterSynopsis = ps;
posterFilename = pfn;
posterRemoteLocation = fl;
}
public int getPosterID(){
return this.posterId;
}
public int getCatID(){
return this.categoryId;
}
public int getEventId(){
return this.eventId;
}
public String getPresenterFname(){
return this.presenterFname;
}
public String getPresenterLname(){
return this.presenterLname;
}
public String getPosterTitle(){
return this.posterTitle;
}
public String getPosterSynopsis(){
return this.posterSynopsis;
}
public String getPosterFilename(){
return this.posterFilename;
}
public String getPosterRemote(){
return this.posterRemoteLocation;
}
}
You can find the class for a custom adapter to vaguely fit your needs below. This will work in pretty much the same way that you are trying to use the general one in your code sample.
This method will give you more flexibility in the way your information is displayed.
You can set the custom layout in the getView method. As well as set the values in the view from the item number passed in.
public class PosterListAdapter extends BaseAdapter {
private final ArrayList<Poster> listItems;
private final LayoutInflater inflater;
public PosterListAdapter(ArrayList<Poster> listItems, LayoutInflater inflater) {
this.listItems = listItems;
this.inflater = inflater;
}
#Override
public int getCount() {
return this.listItems.size();
}
#Override
public Film getItem(int i) {
return this.listItems.get(i);
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null) {
view = inflater.inflate(R.layout.poster_layout, viewGroup, false);
}
Poster item = this.listItems.get(i);
TextView posterTitle = ((TextView) view.findViewById(R.id.poster_layout_title));
posterTitle.setText(item.getTitle());
ImageView posterImage = ((ImageView) view.findViewById(R.id.poster_layout_image));
posterImage.setImageResource(R.drawable.apple);
return view;
}
}
Below you will find a simple layout that can be used with the above array adapter for a list view item.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="vertical">
<ImageView
android:id="#+id/poster_layout_image"
android:layout_width="50dp"
android:layout_height="75dp"
android:layout_centerVertical="true"
android:src="#drawable/ic_launcher" />
<TextView
android:id="#+id/poster_layout_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/poster_layout_image"
android:textColor="#color/text"
android:textSize="20sp" />
</RelativeLayout>
Is there a good tutorial or link that shows how to add different items to a listview?
For example, one with two Text lines and a Check box, another that you just press and and something would pop up. All I have now is every list item is the same two line text view and checkbox...
Or, if there is a way to add 1 row at a time with a different layout through R.layout.xxx?
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mRoot = inflater.inflate(R.layout.frag_settings, container, false);
mItems = getResources().getStringArray(R.array.setting_items);
mItemDescription = getResources().getStringArray(R.array.setting_item_descriptions);
mItemListView = (ListView) mRoot.findViewById(R.id.lvMainListView);
ArrayAdapter<String> lvRowTitle = new ArrayAdapter<String>(getActivity(),
R.layout.setting_twolinetext_checkbox, R.id.tvRowTitle,
mItems);
mItemListView.setAdapter(lvRowTitle);
ArrayAdapter<String> lvRowDesc = new ArrayAdapter<String>(getActivity(),
R.layout.setting_twolinetext_checkbox, R.id.tvRowDesc,
mItemDescription);
mItemListView.setAdapter(lvRowDesc);
return mRoot;
In my example, the list activity that will display our custom list view is called OptionsActivity, because in my project this activity is going to display the different options my user can set to control my app. There are two list item types, one list item type just has a TextView and the second list item type just has a Button. You can put any widgets you like inside each list item type, but I kept this example simple.
The getItemView method checks to see which list items should be type 1 or type 2. According to my static ints I defined up top, the first 5 list items will be list item type 1, and the last 5 list items will be list item type 2. So if you compile and run this, you will have a ListView that has five items that just contain a button, and then five items that just contain a TextView.
Below is the activity code, the activity xml file, and an xml file for each list item type.
OptionsActivity.java:
public class OptionsActivity extends ListActivity {
private static final int LIST_ITEM_TYPE_1 = 0;
private static final int LIST_ITEM_TYPE_2 = 1;
private static final int LIST_ITEM_TYPE_COUNT = 2;
private static final int LIST_ITEM_COUNT = 10;
// The first five list items will be list item type 1
// and the last five will be list item type 2
private static final int LIST_ITEM_TYPE_1_COUNT = 5;
private MyCustomAdapter mAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAdapter = new MyCustomAdapter();
for (int i = 0; i < LIST_ITEM_COUNT; i++) {
if (i < LIST_ITEM_TYPE_1_COUNT)
mAdapter.addItem("item type 1");
else
mAdapter.addItem("item type 2");
}
setListAdapter(mAdapter);
}
private class MyCustomAdapter extends BaseAdapter {
private ArrayList<String> mData = new ArrayList<String>();
private LayoutInflater mInflater;
public MyCustomAdapter() {
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void addItem(final String item) {
mData.add(item);
notifyDataSetChanged();
}
#Override
public int getItemViewType(int position) {
if(position < LIST_ITEM_TYPE_1_COUNT)
return LIST_ITEM_TYPE_1;
else
return LIST_ITEM_TYPE_2;
}
#Override
public int getViewTypeCount() {
return LIST_ITEM_TYPE_COUNT;
}
#Override
public int getCount() {
return mData.size();
}
#Override
public String getItem(int position) {
return mData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
int type = getItemViewType(position);
if (convertView == null) {
holder = new ViewHolder();
switch(type) {
case LIST_ITEM_TYPE_1:
convertView = mInflater.inflate(R.layout.list_item_type1, null);
holder.textView = (TextView)convertView.findViewById(R.id.list_item_type1_text_view);
break;
case LIST_ITEM_TYPE_2:
convertView = mInflater.inflate(R.layout.list_item_type2, null);
holder.textView = (TextView)convertView.findViewById(R.id.list_item_type2_button);
break;
}
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
holder.textView.setText(mData.get(position));
return convertView;
}
}
public static class ViewHolder {
public TextView textView;
}
}
activity_options.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ListView
android:id="#+id/optionsList"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
list_item_type_1.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/list_item_type1_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/list_item_type1_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text goes here" />
</LinearLayout>
list_item_type2.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/list_item_type2_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/list_item_type2_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button text goes here" />
</LinearLayout>
You have two possibilities to do that:
Create a Type and check for your type and return the view related to this type.
BaseAdapter has two methods to check different items in it, getItemViewType(int position) and getViewTypeCount(). Do your stuff there.
Check this tutorial:
ListView with multiple rows
You should create your own class extending BaseAdapter. I recommend watching The World of ListView, it will help you understand everything you need to know about working with ListView.
In addition to #LouMorda answer, I'd use some class, with fields that contains info about item and list item type:
public class Item {
private int itemViewType;
private Object tag;
private String title;
public Item(int itemViewType){
this.itemViewType = itemViewType;
}
public int getItemViewType() {
return itemViewType;
}
public void setItemViewType(int itemViewType) {
this.itemViewType = itemViewType;
}
...
}
So using this object gives more flexibility when adding items to the list in different sequences:
public class OptionsActivity extends ListActivity {
private static final int LIST_ITEM_TYPE_1 = 0;
private static final int LIST_ITEM_TYPE_2 = 1;
private ArrayList<String> mItemsSource = new ArrayList<>();
...
#Override
public int getItemViewType(int position) {
return mItemsSource.get(position).getItemViewType();
}
...
}
How to change an image in my specific gridview as I get the below error. I have followed similar examples elsewhere without success. ie I get "cannot change from integer to imageview" when trying the below, from
(see Android GridView - update View based on position), i.e.:
int tempid = v.getId();
ImageView imgView = FruitToChooseFromImages.get(tempid);
imgView.setBackgroundResource(R.drawable.blank);
I have also tried:
{ // remove viewable image / make blank
ImageView imageView = (ImageView) v;
imageView.setImageResource(R.drawable.blank);
}
FULL CODE BELOW IF YOU NEED IT:
Main JAVA code:
public class game1mainscreen extends Activity {
private MyGridviewAdapter1 mAdapter;
private GridView gridview;
private ArrayList<Integer> FruitToChooseFromImages;
private ArrayList<Integer> tempintarray;
int Totalfruit = 11; // starting from 0 of course (so an 11=12 fruit) this means there are 6 pairs of fruit to select
int fruitleft = 12;
int fruitstilltoadd = Totalfruit + 1;
int numberOfFruitToRemove = 6;
int puthere = 0;
int imagesSelectedThusFar = 0;
int Fruitleft = 0;
int firstfruitselected = R.drawable.blank; int firstfruitselpos;
int secondfruitselected = R.drawable.blank; int secondfruitselpos;
int removefirstimage = 0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gameonemenu);
{
FruitToChooseFromImages = new ArrayList<Integer>();
FruitToChooseFromImages.add(R.drawable.fruit0);
.....etc....
FruitToChooseFromImages.add(R.drawable.fruit11);
}
...code removed which randomly sorts FruitToChooseFromImages (ie arraylist of images) into 6 duplicate pairs of images...
// prepared arraylist is passed to the Adapter class
mAdapter = new MyGridviewAdapter1(this, FruitToChooseFromImages);
// Set custom adapter to gridview
gridview = (GridView) findViewById(R.id.gridView1);
gridview.setAdapter(mAdapter);
// DO THIS WHEN CLICKED
gridview.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
{
int fruitselected = (int)FruitToChooseFromImages.get(position);
// start
if (fruitselected == R.drawable.blank)
{
// if blank/empty icon clicked on then DO NOTHING
}
else
{ // firstly, say fruit name
int soundtoplaynow = getrightsound(position, fruitselected);
SoundManager.playSound(soundtoplaynow, 1);
// next
if (imagesSelectedThusFar == 0)
{
imagesSelectedThusFar = 1;
firstfruitselected = fruitselected; firstfruitselpos = position;
//both switch fruit image to blank in the array and display blank at position clicked
FruitToChooseFromImages.set(position, R.drawable.blank);
{ // remove viewable image / make blank
ImageView imageView = (ImageView) v;
imageView.setImageResource(R.drawable.blank);
}
}
else // so two images have been selected! do they match?
{
imagesSelectedThusFar = 0; // has reached 2, so reset to zero
secondfruitselected = fruitselected; secondfruitselpos = position;
if (firstfruitselected == secondfruitselected)
{
GeneralSoundManager.playSound(0, 1);// play happy sound - change code to GeneralSoundManager
//switch fruit image to blank and display blank at position clicked **
FruitToChooseFromImages.set (position, R.drawable.blank);
{ // remove viewable image / make blank
ImageView imageView = (ImageView) v;
imageView.setImageResource(R.drawable.blank);
}
int tempid = v.getId();
ImageView imgView = FruitToChooseFromImages.get(tempid);
imgView.setBackgroundResource(R.drawable.blank);
fruitleft = (fruitleft - 2);
}
else
{ // you selected the wrong fruit, sorry.
GeneralSoundManager.playSound(1, 1);
FruitToChooseFromImages.set (firstfruitselpos, firstfruitselected);
//
}
}
}
// end
if (fruitleft == 0)
{
//end game - add code here
}
}
});
}
// returns the sound to play depending on what image was clicked on
public int getrightsound(Integer position, Integer switchused) {
...etc....
return soundtoplay;
}
}
My gridview adapter code:
public class MyGridviewAdapter1 extends BaseAdapter
{
private ArrayList<Integer> FruitToChooseFromImages;
private Activity activity;
public MyGridviewAdapter1(Activity activity,ArrayList<Integer> FruitToChooseFromImages)
{
super();
this.FruitToChooseFromImages = FruitToChooseFromImages;
this.activity = activity;
}
public int getCount() {
return FruitToChooseFromImages.size();
}
public Integer getItem(int position) {
return FruitToChooseFromImages.get(position);
}
public long getItemId(int position) {
return 0;
}
public static class ViewHolder
{
public ImageView imgViewFlag;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder view;
LayoutInflater inflator = activity.getLayoutInflater();
if(convertView==null)
{
view = new ViewHolder();
convertView = inflator.inflate(R.layout.gridview_row, null);
view.imgViewFlag = (ImageView) convertView.findViewById(R.id.imageView1);
convertView.setTag(view);
}
else
{
view = (ViewHolder) convertView.getTag();
}
view.imgViewFlag.setImageResource(FruitToChooseFromImages.get(position));
return convertView;
}
}
My Main xml code - gameonemenu:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:gravity="center"
android:layout_gravity="center"
android:background="#drawable/tree">
<GridView
android:id="#+id/gridView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:numColumns="4"
android:verticalSpacing="1dp"
android:horizontalSpacing="1dp"
android:stretchMode="columnWidth"
android:gravity="center" />
</LinearLayout>
My Grirdview_row xml code:
<ImageView
android:layout_height="64dp"
android:id="#+id/imageView1"
android:layout_width="64dp"
android:src="#drawable/blank"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true">
</ImageView>
</RelativeLayout>
PS I used Grirdview_row xml which originally showed text but I don't need to display text only images but is this causing an issue?
PSS please keep your advice at the COMPLETE beginner level and include code if possible to match explanation. I cannot stress this enough. Thanks.