Okey so, since I've not found a consistent way of doing this when I searched, I decided that maybe putting my code for somebody elses eyes to see might help.
I'm creating a game where you use cards. These cards can either be locked or unlocked depending on different factors. The important thing is, that I want to check the sqlite db whether they are locked, then display different row layouts for the two possible outcomes.
Here's my code:
public class AllCardsAdapter extends CursorAdapter {
LockedHolder viewLocked;
UnlockedHolder viewUnlocked;
private LayoutInflater mInflater;
public static final int LOCKED = 0;
public static final int UNLOCKED = 1;
public AllCardsAdapter(Context context, Cursor cursor) {
super(context, cursor);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
final int type;
int viewType = this.getItemViewType(cursor.getInt(cursor.getColumnIndex("unlocked")));
if (viewType == 1){
type = UNLOCKED;
} else {
type = LOCKED;
}
if (type == LOCKED){
viewLocked = (LockedHolder) view.getTag();
viewLocked.nameHolder.setText(cursor.getString(cursor.getColumnIndex("name")));
viewLocked.awardedAtHolder.setText("Awarded at level:");
viewLocked.reqLvlHolder.setText(cursor.getString(cursor.getColumnIndex("reqlvl")));
String imagePath = cursor.getString(cursor.getColumnIndex("image"));
if (imagePath.equals("card_obj_plus_1")){
Picasso.with(context).load(R.drawable.card_obj_plus_1).placeholder(R.drawable.card_placeholder).into(viewLocked.imageHolder);
}
if (imagePath.equals("card_obj_plus_2")){
Picasso.with(context).load(R.drawable.card_obj_plus_2).placeholder(R.drawable.card_placeholder).into(viewLocked.imageHolder);
}
if (imagePath.equals("card_obj_plus_3")){
Picasso.with(context).load(R.drawable.card_obj_plus_3).placeholder(R.drawable.card_placeholder).into(viewLocked.imageHolder);
}
if (imagePath.equals("card_slowdown")){
Picasso.with(context).load(R.drawable.card_slowdown).placeholder(R.drawable.card_placeholder).into(viewLocked.imageHolder);
}
if (imagePath.equals("card_speed_up")){
Picasso.with(context).load(R.drawable.card_speed_up).placeholder(R.drawable.card_placeholder).into(viewLocked.imageHolder);
}
} else {
viewUnlocked = (UnlockedHolder) view.getTag();
viewUnlocked.nameHolder.setText(cursor.getString(cursor.getColumnIndex("name")));
String imagePath = cursor.getString(cursor.getColumnIndex("image"));
if (imagePath.equals("card_obj_plus_1")){
Picasso.with(context).load(R.drawable.card_obj_plus_1).placeholder(R.drawable.card_placeholder).into(viewUnlocked.imageHolder);
}
if (imagePath.equals("card_obj_plus_2")){
Picasso.with(context).load(R.drawable.card_obj_plus_2).placeholder(R.drawable.card_placeholder).into(viewUnlocked.imageHolder);
}
if (imagePath.equals("card_obj_plus_3")){
Picasso.with(context).load(R.drawable.card_obj_plus_3).placeholder(R.drawable.card_placeholder).into(viewUnlocked.imageHolder);
}
if (imagePath.equals("card_slowdown")){
Picasso.with(context).load(R.drawable.card_slowdown).placeholder(R.drawable.card_placeholder).into(viewUnlocked.imageHolder);
}
if (imagePath.equals("card_speed_up")){
Picasso.with(context).load(R.drawable.card_speed_up).placeholder(R.drawable.card_placeholder).into(viewUnlocked.imageHolder);
}
}
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
viewLocked = new LockedHolder();
viewUnlocked = new UnlockedHolder();
final int type;
int viewType = this.getItemViewType(cursor.getInt(cursor.getColumnIndex("unlocked")));
if (viewType == 1){
type = UNLOCKED;
} else {
type = LOCKED;
}
System.out.println(viewType);
System.out.println(type);
if (type == LOCKED){
View lockedView;
lockedView = mInflater.inflate(R.layout.card_list_row_disabled, parent, false);
viewLocked.nameHolder = (TextView) lockedView.findViewById(R.id.txtTitle);
viewLocked.imageHolder = (ImageView) lockedView.findViewById(R.id.imgThumbnail);
viewLocked.reqLvlHolder = (TextView) lockedView.findViewById(R.id.tvLevelNr);
viewLocked.awardedAtHolder = (TextView) lockedView.findViewById(R.id.tvAwardedAt);
lockedView.setTag(viewLocked);
return lockedView;
} else {
View unlockedView;
unlockedView = mInflater.inflate(R.layout.card_list_row, parent, false);
viewUnlocked.nameHolder = (TextView) unlockedView.findViewById(R.id.txtTitle);
viewUnlocked.imageHolder = (ImageView) unlockedView.findViewById(R.id.imgThumbnail);
unlockedView.setTag(viewUnlocked);
return unlockedView;
}
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int position) {
return position % 2;
}
public class LockedHolder {
public TextView nameHolder;
public ImageView imageHolder;
public TextView awardedAtHolder;
public TextView reqLvlHolder;
}
public class UnlockedHolder {
public TextView nameHolder;
public ImageView imageHolder;
}
}
The error I'm getting is on the row "viewLocked = (LockedHolder) view.getTag();"
AllCardsAdapter$UnlockedHolder cannot be cast to AllCardsAdapter$LockedHolder
The error only shows up when I have a list containing cards that are both locked and unlocked.
See I know what it's trying to do, I just don't know why. Also, if I'm overcomplicating things for no good reason, or missing something obvious, I'd be much appreciated if you find it..
getItemViewType implementation does not look right (type does not depend on item position) it should be something like the following
private int getItemViewType(Cursor cursor) {
return cursor.getInt(cursor.getColumnIndex("unlocked")) % 2;
}
#Override
public int getItemViewType(int position) {
Cursor cursor = (Cursor) getItem(position);
return getItemViewType(cursor);
}
You also need to update bindView and newView
int viewType = this.getItemViewType(cursor);
Related
I have a listview and a button in my main activity and three layout ressource files (right.xml, mid.xml and left.xml [They're relative layout]).
I want to make an arrayList (with strings and drawable (images)) and each time I push the button in main.xml the first content of the arrayList will appear at the bottom of the screen (either left, mid or right --> depend of the order of the arrayList) and when I click again the next item (string or drawable) will appear beneath it, pushing it in an upward motion.
UPDATE
I made a Model and an Adapter
Here is the model
public class ModelC1 {
public String C1Name;
public String C1Text;
public int id;
public boolean isSend;
public ModelC1(String C1Name, String C1Text, int id, boolean isSend){
this.id = id;
this.C1Name = C1Name;
this.C1Text = C1Text;
this.isSend = isSend;
}
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public String getC1Name() {
return C1Name;
}
public void setC1Name(String C1Name){
this.C1Name = C1Name;
}
public String getC1Text() {
return C1Text;
}
public void setC1Text (String C1Text){
this.C1Text = C1Text ;
}
public boolean isSend() {
return isSend;
}
public void setIsSend(boolean send){
isSend = send;
}
Here is the Adapter
public class AdapterC1 extends BaseAdapter {
private List<ModelC1> listChat;
private LayoutInflater inflater;
private Context context;
public AdapterC1(List<ModelC1> listChat, Context context){
this.listChat = listChat;
this.context = context;
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return listChat.size();
}
#Override
public Object getItem(int i) {
return listChat.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
View vi = convertView;
if(convertView == null ){
if(listChat.get(i).isSend() == 0)
vi=inflater.inflate(R.layout.list_send,null);
else if ((listChat.get(i).isSend() == 1))
vi=inflater.inflate(R.layout.list_recv,null);
else if ((listChat.get(i).isSend() == 2))
vi=inflater.inflate(R.layout.list_mid,null);
}else{
if(listChat.get(i).isSend() == 0)
vi=inflater.inflate(R.layout.list_send,null);
else if ((listChat.get(i).isSend() == 1))
vi=inflater.inflate(R.layout.list_recv,null);
else if ((listChat.get(i).isSend() == 2))
vi=inflater.inflate(R.layout.list_mid,null);
}
if(listChat.get(i).isSend() !=0 || listChat.get(i).isSend() !=1 || listChat.get(i).isSend() !=2 ){
BubbleTextView bubbleTextView = (BubbleTextView) vi.findViewById(R.id.bubbleChat);
if(bubbleTextView != null)
bubbleTextView.setText(listChat.get(i).C1Text);
TextView nameTextView = (TextView) vi.findViewById(R.id.nameChat);
if(nameTextView != null)
nameTextView.setText(listChat.get(i).C1Name);
}else{
vi=inflater.inflate(R.layout.list_mid,null);
BubbleTextView bubbleTextView = (BubbleTextView) vi.findViewById(R.id.bubbleChat);
bubbleTextView.setText("THE END");
}
return vi;
}
And here is the activity
public class Chat1 extends AppCompatActivity {
private static final String TAG = "Chat1";
private AdapterC1 adapter;
private List<ModelC1> listChat = new ArrayList<>();
private int count = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat1);
RecyclerView chatContent1 = findViewById(R.id.chatContent1);
}
private ModelC1 setUpMessage(){
Log.d(TAG, "setUpMessage: Exec");
return();
}
///OnClick of the button in the activity_chat1.xml
public void nextClicked1(View view) {
Log.d(TAG, "nextClicked: Is Clicked");
///After the limit of the arraylist is reached
final int limit = 40;
if(count == limit){
Log.d(TAG, "nextClicked: Limit Reached");
Intent i = new Intent(Chat1.this, MainActivity.class);
startActivity(i);
}else{
///Call the list
loadList(null);
}
}
///Load the list of arrays?
public void loadList(View view){
ModelC1 chat = setUpMessage();
listChat.add(chat);
///The ID of the recycleview in the activity_chat1.xml
final RecyclerView recyclerview = findViewById(R.id.chatContent1);
///The adapter
final AdapterC1 adapter = new AdapterC1(listChat, this);
///Make the recyclerview always scroll
///the adapter
///recyclerview.setAdapter(adapter);
}
My questions are now how do I make the ArrayList (containing strings and drawables) and how to link the ArrayList to make it appear one by one when I click on the button ?
As for the ArrayList, will soemthing like that works ?
private List<List<String>> textChat1 = new ArrayList<List<String>>();
ArrayList<String> textChat1 = new ArrayList<String>();
textChat1.add("This is message 1");
textChat1.add("This is message 2");
textChat1.add("This is message 2");
addresses.add(textChat1);
How can I add images and how to say which strings inflate which layout (left, mid or right) ?
You can do your job like this: in your Adapter's getView method ,
#Override
public View getView(int position, View convertView, ViewGroup container) {
if (convertView == null) {
if (position == 1) {
convertView = getLayoutInflater().inflate(R.layout.left, container, false);
} else if (position == 2) {
convertView = getLayoutInflater().inflate(R.layout.mid, container, false);
} else {
convertView = getLayoutInflater().inflate(R.layout.right, container, false);
}
}
//your code here
return convertView;
}
This will do your job, but, I suggest you to use Recyclerview because it's more efficient and better in terms of looks as well as memory management.
I am trying to make an application with a ListView that include a Country Flag and name. This is so that the user can click on them and be shown images of the country that they wouldve taken before. However for about 3 seconds when the listview loads if i try to scroll it will sort of glitch and send me back to top. This is the code..
public class CountriesListAdapter extends ArrayAdapter {
private int resource;
private LayoutInflater inflater;
private List<CountryModel> countryModels;
private WeakReference<TextView> selectedCountryIdtxt;
private boolean useFilter;
private WeakReference<ProgressBar> progressBarWeakReference;
public int getSelectedCountryId() {
return selectedCountryId;
}
public void setSelectedCountryId(int selectedCountryId) {
this.selectedCountryId = selectedCountryId;
}
private int selectedCountryId;
public CountriesListAdapter(#NonNull WeakReference<Context> context, int resourceId, WeakReference<TextView> textView, #NonNull List<CountryModel> countryModelList, boolean useFilter, WeakReference<ProgressBar> progressBarWeakReference){
super(context.get(), resourceId, countryModelList);
selectedCountryIdtxt = textView;
resource = resourceId; //the id of the template file
inflater = LayoutInflater.from(context.get());
this.countryModels = countryModelList;
selectedCountryId = -1;
this.useFilter = useFilter;
this.progressBarWeakReference = progressBarWeakReference;
}
public int getCount() {
if (countryModels != null)
return countryModels.size();
return 0;
}
public CountryModel getItem(int position) {
if (countryModels != null)
return countryModels.get(position);
return null;
}
public long getItemId(int position) {
if (countryModels != null)
return countryModels.get(position).hashCode();
return 0;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
// this method is automatically called for every object in our list
//basically it's called for every single row before it is generated
// this method is called per row
convertView = (ConstraintLayout) inflater.inflate(resource, null);
//the variable countryModel is fiiled with current object that is being processed
final CountryModel countryModel = countryModels.get(position);
TextView countryName = convertView.findViewById(R.id.countryNamelbl);
final ImageView countryFlag = convertView.findViewById(R.id.countryFlagimg);
final ImageView checked = convertView.findViewById(R.id.countryCheckedimg);
//this is done for every object in the list
assert countryModel != null;
countryName.setText(countryModel.getName());
Picasso.get().load(countryModel.getImage()).fit().into(countryFlag);
if(!useFilter) {
if (selectedCountryId == countryModel.getId()) {
checked.setVisibility(View.VISIBLE);
} else {
checked.setVisibility(View.INVISIBLE);
}
}
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(!useFilter) {
if (checked.getVisibility() == View.VISIBLE) {
checked.setVisibility(View.INVISIBLE);
selectedCountryId = -1;
selectedCountryIdtxt.get().setText(String.valueOf(selectedCountryId));
} else {
if (selectedCountryId == -1) {
checked.setVisibility(View.VISIBLE);
selectedCountryId = countryModel.getId();
} else {
selectedCountryId = countryModel.getId();
notifyDataSetChanged();
}
selectedCountryIdtxt.get().setText(String.valueOf(selectedCountryId));
}
} else {
Intent i = new Intent(getContext(), PicturesActivity.class);
i.putExtra("countryId",countryModel.getId());
i.putExtra("countryName", countryModel.getName());
getContext().startActivity(i);
}
}
});
progressBarWeakReference.get().setVisibility(View.INVISIBLE);
return convertView;
}
public List<CountryModel> getCountryModels() {
return countryModels;
}
public void setCountryModels(List<CountryModel> countryModels) {
this.countryModels = countryModels;
}
}
The problem was actually in another class, i was calling the adapter for every list item instead of just once... oops.
Thanks for the replies though!
Please tell me what I'm doing wrong? I adapter receives data from the server and places them in the foliage. Then, when new data arrive, I try to update the adapter ... and as if all is well, but when it comes .. the new data, eg 2 messages, they are added to the adapter. But with the new data are added to all the other old dannye..Hotya logs on can see that the old data received I do not have a server. It turns out that it is not doing data.clear (). I carry ... data.clear (), my foliage becomes completely empty until the next request Handler.postDelayed () ;. Again request - full foliage and the new data ... 5 seconds passed and my clean sheet again ... and so constantly. How to overcome it?
My Adapter:
public class ChatMsgAdapter extends ArrayAdapter<ResponseMsgArray> {
private Context context;
private ArrayList<ResponseMsgArray> data;
protected String LV_KEY = Auth.key;
protected int LV_USID = Integer.parseInt(Auth.id);
protected int GET_ID = Integer.parseInt(FriendActivity.get_id);
String LOG_TAG = "FriendLOG";
public ChatMsgAdapter(Context context, ArrayList<ResponseMsgArray> values) {
super(context,R.layout.activity_friend_msg, values);
this.data = values;
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View v;
int type = getItemViewType(position);
if(type == LV_USID) {
v = inflater.inflate(R.layout.activity_friend_msg_adapter, null);
TextView user_id_msg = (TextView) v.findViewById(R.id.id_msg);
TextView user_text = (TextView) v.findViewById(R.id.msg);
TextView user_date = (TextView) v.findViewById(R.id.msg_time);
user_text.setText(data.get(position).getMsg());
user_date.setText(data.get(position).getMsg_time());
user_id_msg.setText(data.get(position).getMsg_id());
} else if (type == GET_ID) {
v = inflater.inflate(R.layout.talker, null);
TextView talker_text = (TextView) v.findViewById(R.id.msg);
TextView talker_date = (TextView) v.findViewById(R.id.msg_time);
talker_text.setText(data.get(position).getMsg());
talker_date.setText(data.get(position).getMsg_time());
} else {
//Если нет например сообщений
v = inflater.inflate(R.layout.msg_null, null);
}
return v;
}
public void setData(ArrayList<ResponseMsgArray> newData) {
addAll(newData);
notifyDataSetChanged();
}
#Override
public int getItemViewType(int position) {
int newPosition = Integer.parseInt(data.get(position).getMsg_id_us());
return newPosition;
}
}
Text translated with the help of an interpreter. Thank you for understanding.
Here in this post https://ru.stackoverflow.com/questions/579311/%d0%9f%d0%b5%d1%80%d0%b5%d0%b4%d0%b0%d1%87%d0%b0-%d0%b4%d0%b0%d0%bd%d0%bd%d1%8b%d1%85-%d0%b2-%d0%b4%d1%80%d1%83%d0%b3%d0%be%d0%b9-%d0%ba%d0%bb%d0%b0%d1%81%d1%81/579403?noredirect=1#comment769066_579403 are all my current classes
I have a very specific problem. I'm creating a word list app that basically lets me enter some words and their meanings and stores them in an SQLite database and then it shows them back to me. I've made my own content provider to handle all these interactions. I store the words in one table and the definitions in another table and these two tables are linked together through the books' unique id. I'm also using a CursorLoader and a CursorAdapter to populate my listView in my MainActivity. Now my problem is when I get the list of the words that I have in my database, some of the words have more than one definition and I have to query against the database as I'm drawing each list item in my listView to find the definitions and put them on the list. This has caused my listView to stutter. I've even tried to use AsyncTask but I don't want to start a new thread every time a word is getting added to my listView at runtime. Is there any efficient, right way to do this?
This is my CursorAdapter class where I believe is the source of the problem.
public class WordAdapter extends CursorAdapter {
public static final String[] definitionsProjection = {
Definitions._ID,
Definitions.COLUMN_TEXT,
Definitions.COLUMN_POS
};
public static final String[] examplesProjection = {
Examples._ID,
Examples.COLUMN_TITLE,
Examples.COLUMN_TEXT,
Examples.COLUMN_URL
};
public static final int DEFINITIONS_COLUMN_TEXT = 1;
public static final int DEFINITIONS_COLUMN_POS = 2;
public static final int EXAMPLES_COLUMN_TITLE = 1;
public static final int EXAMPLES_COLUMN_TEXT = 2;
public static final int EXAMPLES_COLUMN_URL = 3;
private static final int VIEW_TYPE_TODAY = 0;
private static final int VIEW_TYPE_OLD = 1;
public WordAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int position) {
if(position == 0) {
return VIEW_TYPE_TODAY;
} else {
return VIEW_TYPE_OLD;
}
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
int viewType = getItemViewType(cursor.getPosition());
int layoutId = -1;
if(viewType == VIEW_TYPE_TODAY) {
layoutId = R.layout.list_item_today;
} else if(viewType == VIEW_TYPE_OLD) {
layoutId = R.layout.list_item_word;
}
View view = LayoutInflater.from(context).inflate(layoutId, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
return view;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
int viewType = getItemViewType(cursor.getPosition());
String wordId = cursor.getString(MainFragment.WORDS_ID);
viewHolder.wordView.setText(wordId + " / " + cursor.getString(MainFragment.WORDS_COLUMN_WORD));
FetchDefinitions fetchDefinitions = new FetchDefinitions(context, view);
fetchDefinitions.execute(wordId);
switch (viewType) {
case VIEW_TYPE_TODAY:
{
viewHolder.noteView.setText(cursor.getString(MainFragment.WORDS_COLUMN_NOTE));
Cursor exampleCursor = context.getContentResolver().query(
Examples.CONTENT_URI.buildUpon().appendPath(wordId).build(),
examplesProjection,
null,
null,
null
);
exampleCursor.moveToFirst();
viewHolder.exampleOneView.setText(exampleCursor.getString(EXAMPLES_COLUMN_TITLE));
if(exampleCursor.getCount() > 1) {
exampleCursor.moveToNext();
viewHolder.exampleTwoView.setText(exampleCursor.getString(EXAMPLES_COLUMN_TITLE));
} else {
viewHolder.exampleTwoView.setVisibility(View.GONE);
}
exampleCursor.close();
break;
}
}
viewHolder.flagView.setText("Flag " + Utility.flagsToString(cursor.getInt(MainFragment.WORDS_COLUMN_FLAG)));
viewHolder.sourceView.setText("Source " + cursor.getString(MainFragment.WORDS_COLUMN_SOURCE));
viewHolder.dateView.setText(Utility.convertDateToUXFormat(cursor.getInt(MainFragment.WORDS_COLUMN_DATE)));
}
private static class ViewHolder {
public final TextView wordView;
public final TextView noteView;
public final TextView exampleOneView;
public final TextView exampleTwoView;
public final TextView flagView;
public final TextView sourceView;
public final TextView dateView;
private ViewHolder(View view) {
wordView = (TextView) view.findViewById(R.id.word_textView);
noteView = (TextView) view.findViewById(R.id.note_textView);
exampleOneView = (TextView) view.findViewById(R.id.example_1_textView);
exampleTwoView = (TextView) view.findViewById(R.id.example_2_textView);
flagView = (TextView) view.findViewById(R.id.flag_textView);
sourceView = (TextView) view.findViewById(R.id.source_textView);
dateView = (TextView) view.findViewById(R.id.date_textView);
}
}
private class FetchDefinitions extends AsyncTask<String, Void, Cursor> {
private Context bgContext;
private View bgView;
public TextView posOneView;
public TextView posTwoView;
public TextView definitionOneView;
public TextView definitionTwoView;
public FetchDefinitions(Context context, View view) {
this.bgContext = context;
this.bgView = view;
}
#Override
protected Cursor doInBackground(String... params) {
String wordId = params[0];
return bgContext.getContentResolver().query(
Definitions.CONTENT_URI.buildUpon().appendPath(wordId).build(),
definitionsProjection,
null,
null,
null
);
}
#Override
protected void onPostExecute(Cursor cursor) {
if(cursor != null) {
cursor.moveToFirst();
posOneView = (TextView) bgView.findViewById(R.id.pos_1_textView);
definitionOneView = (TextView) bgView.findViewById(R.id.definition_1_textView);
posOneView.setText(cursor.getString(DEFINITIONS_COLUMN_POS));
definitionOneView.setText(cursor.getString(DEFINITIONS_COLUMN_TEXT));
posTwoView = (TextView) bgView.findViewById(R.id.pos_2_textView);
definitionTwoView = (TextView) bgView.findViewById(R.id.definition_2_textView);
if(cursor.getCount() > 1) {
cursor.moveToNext();
posTwoView.setText(cursor.getString(DEFINITIONS_COLUMN_POS));
definitionTwoView.setText(cursor.getString(DEFINITIONS_COLUMN_TEXT));
} else {
posTwoView.setVisibility(View.GONE);
definitionTwoView.setVisibility(View.GONE);
}
}
}
}
}
I want to change the row layout when an specific button(action) is made.
public class DbCursorAdapter extends CursorAdapter {
private View selectedView;
private boolean isListSingleColumn = true;
private Cursor mCursor;
private final LayoutInflater mInflater;
private static final int TYPE_ITEM_SINGLE_COLUMN = 0;
private static final int TYPE_ITEM_MULTI_COLUMN = 1;
/**
* DbCursorAdapter constructor
*
* #param context
* - The context
* #param cursor
* - The cursor used to make queries
*/
public DbCursorAdapter(Context context, Cursor cursor) {
super(context, cursor, false);
this.mContext = context;
this.mCursor = cursor;
this.mInflater = LayoutInflater.from(context);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
final ViewHolder holder = (ViewHolder) view.getTag();
String collection = mCursor.getString(mCursor
.getColumnIndex(DatabaseHelper.COLUMN_COLLECTION));
String fileName = mCursor.getString(mCursor
.getColumnIndex(DatabaseHelper.COLUMN_FILE_NAME));
holder.title.setText(fileName);
if (collection.equals("true")) {
// different folder icon for multi-column list
holder.icon
.setImageResource(isListSingleColumn ? R.drawable.ic_file_folder2
: R.drawable.ic_file_folder);
holder.details.setText("");
} else {
String extension = fileName
.substring(fileName.lastIndexOf(".") + 1);
extension = extension.toLowerCase();
String size = mCursor.getString(mCursor
.getColumnIndex(DatabaseHelper.COLUMN_RESOURCE_LENGTH));
String actualSize = MemoryManagerHelper.getInstance().getFileSize(
Float.parseFloat(size));
holder.icon.setImageResource(Utils.INSTANCE
.getImageResourceForFileType(extension));
holder.details.setText(actualSize);
}
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
/*
* Inflates the item layout. Stores resource IDs in a in a ViewHolder
* class to prevent having to look them up each time bindView() is
* called.
*/
final View itemView = mInflater.inflate(
isListSingleColumn ? R.layout.explorer_row_single_column
: R.layout.explorer_row_multi_column, viewGroup, false);
final ViewHolder holder = new ViewHolder();
holder.title = (TextView) itemView.findViewById(R.id.rowtitle);
holder.details = (TextView) itemView.findViewById(R.id.rowSubtitle);
holder.icon = (ImageView) itemView.findViewById(R.id.icon);
itemView.setTag(holder);
return itemView;
}
#Override
public int getItemViewType(int position) {
return isListSingleColumn ? TYPE_ITEM_SINGLE_COLUMN
: TYPE_ITEM_MULTI_COLUMN;
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public void changeCursor(Cursor cursor) {
super.changeCursor(cursor);
this.mCursor = cursor;
}
/**
* #return <b>true</b> if there is an item selected, <b>false</b> otherwise.
*/
public boolean getSelectedItemState() {
return null == selectedView ? false : true;
}
/**
* Set the selected item.
*
* #param view
* The item which will be set as selected
*/
public void setSelectedItem(View view) {
selectedView = view;
view.setBackgroundResource(R.drawable.explorer_row_selected);
}
/**
* If any item is selected we clear that item.
*/
public void clearSelectedItem() {
if (null != selectedView) {
selectedView.setBackgroundResource(android.R.color.transparent);
// invalidate the selected item
selectedView = null;
}
}
private class ViewHolder {
private TextView title;
private TextView details;
private ImageView icon;
}
public boolean isListSingleColumn() {
return isListSingleColumn;
}
public void setListSingleColumn(boolean isListSingleColumn) {
this.isListSingleColumn = isListSingleColumn;
}
The problem is that the layout isn't changed correctly for all items, some are displayed with the layout changed and some aren't. Also, when scrolling the layout for the items seem to change, sometimes it takes the correct layout, sometimes it takes the wrong layout.
I added an little workaround, detecting when the wrong layout is used and I tried to manually create the correct view, but this doesn't seem work.
Here is how I call my CursorAdapter:
/**
* Change the number of columns the list view will upgrade.
*
* #param item
* - The menu action button for the toggle option
*/
private void changeGridColumns(MenuItem item) {
if (isListSingleColumn) {
listview.setNumColumns(2);
item.setIcon(R.drawable.ic_menu_listgrid2);
mAdapter.setListSingleColumn(false);
mAdapter.notifyDataSetChanged();
} else {
// Set to display list with only 1 column
listview.setNumColumns(1);
item.setIcon(R.drawable.ic_menu_listgrid);
mAdapter.setListSingleColumn(true);
mAdapter.notifyDataSetChanged();
}
isListSingleColumn = !isListSingleColumn;
mAdapter.clearSelectedItem();
}
How can I fix this issue?
That's not how you should be managing the layout change of the items. You should use the getItemViewType() and getViewTypeCount methods:
public static final int SINGLE = 0;
public static final int MULTIPLE = 1;
#Override
public int getItemViewType(int position) {
return isListSingleColumn ? SINGLE : MULTIPLE; // call notifyDataSetChanged when you modify isListSingleColumn
}
#Override
public int getViewTypeCount() {
return 2;
}
// in the newView() method:
final int position = cursor.getPosition();
final int type = getItemViewType(position);
View itemView
if (type == SINGLE) {
itemView = mInflater.inflate(R.layout.explorer_row_single_column, viewGroup, false);
} else {
itemView = mInflater.inflate(R.layout.explorer_row_multi_column, viewGroup, false);
}
// rest of the code
Also, as its name implies, the bindView() method is to be used to bind data to the row view that you receive, I don't see why did you built the item's row again there.
I think I fixed the issue by using overriding getItemViewType method:
#Override
public int getItemViewType(int position) {
return isListSingleColumn ? TYPE_ITEM_SINGLE_COLUMN
: TYPE_ITEM_MULTI_COLUMN;
}
#Override
public int getViewTypeCount() {
return 2;
}
I will also updated the code.