Everything work fine before i implement the json things. When i click the detail button(imageView), dialogFragment should be pop up. It is okay with the pop up, the problem is, it's generate two or more dialogFragment. Is implement json affect the viewholder? Or its related to settag gettag?
Here my code(I used api link from the tutorial) :
RecyclerAdapter :
public class MyVoteMAPOAdapter : RecyclerView.Adapter
{
public List<string> mImageList;
public List<MyVote_Data> mVoteData;
Activity context;
public event EventHandler<int> ItemClick;
public MyVoteMAPOAdapter (Activity context, List<MyVote_Data> data)
{
this.context = context;
mVoteData = data;
}
public override RecyclerView.ViewHolder OnCreateViewHolder (ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.From (parent.Context).Inflate (Resource.Layout.ItemList, parent, false);
ViewHolder vh = new ViewHolder (itemView, OnClick);
itemView.Tag = vh;
return vh;
}
public override void OnBindViewHolder (RecyclerView.ViewHolder holder, int position)
{
//int item = mData[position];
IWindowManager windowManager = context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();
ViewHolder vh = holder as ViewHolder;
setImage (holder, position);
//var imageBitmap = GetImageBitmapFromUrl(mVoteData[position].mPosterImage);
vh.IVDetail.SetTag (Resource.Id.ivDetails, position);
//vh.IVPoster.SetImageBitmap (imageBitmap);
vh.IVDetail.SetImageResource (Resource.Drawable.ic_information);
vh.IVVote.SetImageResource (Resource.Drawable.undi_color);
vh.IVPoster.Click += delegate {
Android.App.FragmentTransaction trans = context.FragmentManager.BeginTransaction();
FullImageView fImage = FullImageView.newInstance(position);
vh.IVPoster.SetTag(Resource.Id.ivPoster, position);
trans.AddToBackStack(null);
trans.Replace(Resource.Id.place_holder, fImage);
trans.Commit();
};
vh.IVVote.Click += delegate {
if(vh.IVVote.Drawable.GetConstantState().Equals(Resource.Drawable.undi_color)){
vh.IVVote.SetImageResource(Resource.Drawable.undi_grey);
}
else {
vh.IVVote.SetImageResource(Resource.Drawable.undi_color);
}
};
//set a tag for the button to the current clicked position
vh.IVDetail.Click += IVDetail_Click;
vh.TVLike.Text = position.ToString();
}
public void IVDetail_Click (object sender, EventArgs e)
{
//retrieve the tag
int position = (int) (((ImageView) sender).GetTag(Resource.Id.ivDetails));
dialogShow (position);
Console.WriteLine ("KELUARRRRRR!~");
}
public void dialogShow(int position)
{
Android.App.FragmentTransaction transaction = context.FragmentManager.BeginTransaction();
//instantiate a fragment
DetailDialogFragment dialogFragment = DetailDialogFragment.newInstance (mVoteData[position].mName, mVoteData[position].mDescription);
dialogFragment.Show (transaction, "dialog_Fragment");
}
//
public async void setImage(RecyclerView.ViewHolder holder, int position)
{
ViewHolder vh = holder as ViewHolder;
string tempImageString = mVoteData[position].mPosterImage;
var imageBMP = GetImageBitmapFromUrl (tempImageString);
//vh.IVPoster.SetImageBitmap (imageBMP);
vh.IVPoster.SetTag (Resource.Id.ivPoster, position);
if (imageBMP.IsCompleted) {
vh.IVPoster.SetImageBitmap (imageBMP.Result);
} else {
vh.IVPoster.SetImageBitmap (await imageBMP);
}
}
//decode string into bitmap
public async static Task<Bitmap> GetImageBitmapFromUrl(string url)
{
Bitmap imageBitmap = null;
try{
if (url != null)
using (var webClient = new WebClient ()) {
var imageBytes = await webClient.DownloadDataTaskAsync (url);
if (imageBytes != null && imageBytes.Length > 0) {
imageBitmap = BitmapFactory.DecodeByteArray (imageBytes, 0, imageBytes.Length);
}
}
}
catch (Exception e){
Console.WriteLine ("Image Exception : {0}", e);
}
return imageBitmap;
}
public override int ItemCount{
get { return mVoteData.Count; }
}
void OnClick (int position)
{
if (ItemClick != null)
ItemClick (this, position);
}
}
public class ViewHolder : RecyclerView.ViewHolder
{
public ImageView IVPoster { get; private set; }
public TextView TVLike { get; private set; }
public ImageView IVDetail { get; private set; }
public ImageView IVVote { get; private set; }
public ViewHolder (View itemView, Action<int> listener) : base(itemView)
{
IVPoster = itemView.FindViewById <ImageView>(Resource.Id.ivPoster);
TVLike = itemView.FindViewById <TextView>(Resource.Id.tvLike);
IVDetail = itemView.FindViewById <ImageView> (Resource.Id.ivDetails);
IVVote = itemView.FindViewById <ImageView> (Resource.Id.ivVote);
itemView.Click += (sender, e) => listener (base.Position);
}
}
}
Child_Data.cs :
public class MyVote_Data
{
public string mPosterImage { get; set; }
public string mName { get; set; }
public string mDescription { get; set; }
public MyVote_Data ()
{
}
public MyVote_Data(string image, string name, string description)
{
mPosterImage = image;
mName = name;
mDescription = description;
}
public List<MyVote_Data> GetVoteData( string jsonString)
{
string tempImage, temptName, tempDescription;
var myVoteData = new List<MyVote_Data> ();
var data = JsonConvert.DeserializeObject <RootObject2> (jsonString);
foreach (var tempData in data.actors)
{
tempImage = tempData.image;
temptName = tempData.name;
tempDescription = tempData.description;
myVoteData.Add (new MyVote_Data(tempImage, temptName, tempDescription));
}
return myVoteData;
}
}
public class Actor
{
public string name { get; set; }
public string description { get; set; }
public string dob { get; set; }
public string country { get; set; }
public string height { get; set; }
public string spouse { get; set; }
public string children { get; set; }
public string image { get; set; }
}
public class RootObject2
{
public List<Actor> actors { get; set; }
}
There is one issue that I see that sticks out:
vh.IVPoster.Click += delegate {
Android.App.FragmentTransaction trans = context.FragmentManager.BeginTransaction();
FullImageView fImage = FullImageView.newInstance(position);
vh.IVPoster.SetTag(Resource.Id.ivPoster, position);
trans.AddToBackStack(null);
trans.Replace(Resource.Id.place_holder, fImage);
trans.Commit();
};
Every time your re-use your view holder, it still contains the contents of the previous view holder. What you're doing there is your adding an addtional click event handler for every view holder. That is why you're seeing multiple dialog fragments.
What you have to do is unregister the vh.IVPoster.Click event handler before you assigned the new one. So what I would do is refactor your delegate code into an actual method. You can then use "-=" to unregister any previous event handlers and "+=" to register the current event handler.
Update:
I'm doing this by hand, so you'll have to put in a little effort and fix any compile errors and use some basic troubleshooting to get it to work.
So first, create a new method called OnIVPosterClicked:
private void OnIVPosterClicked(object sender, EventArgs e)
{
Android.App.FragmentTransaction trans = context.FragmentManager.BeginTransaction();
FullImageView fImage = FullImageView.newInstance(position);
vh.IVPoster.SetTag(Resource.Id.ivPoster, position);
trans.AddToBackStack(null);
trans.Replace(Resource.Id.place_holder, fImage);
trans.Commit();
}
Then Register your event handler instead of using a delegate:
vh.IVPoster.Click += OnIVPosterClicked;
To Unregister the event handler when ViewHolders get recycled, you'll have to override the:
public override void OnViewRecycled(Java.Lang.Object holder)
{
//Unregister any View specific event handlers
var viewHolder = holder as ViewHolder;
viewHolder.IVPoster.Click -= OnIVPosterClicked;
base.OnViewRecycled(holder);
}
That's the basic gist of it. It probably won't compile if you blindly copy and paste it into your program, so you'll have to fix those. I'm not sure why you're setting tags. With this pattern, that should eliminate the use for keeping track of tags.
Related
i am currently working with recyclerview in Xamarin android where i wish to filter the data displayed. I used to work with java on android and has successfully create a filter on recyclerview with using searchview. But for this one , i wish to display only the incomplete data where either one of the item in the view is empty. Below is my code for activity class and also recyclerview adapter class.Replies with code or explanation would be really helpful. Thank you.
class RemoveAlertActivity : Activity
{
private RecyclerView mRecyclerView_remove;
private RecyclerView.LayoutManager mLayoutManager_remove;
private RecyclerView.Adapter mAdapter_remove;
private List<Removerecyclerholder> mRemoverecyclerholder;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.RemoveAlert);
SQLiteDb obj = new SQLiteDb();
List<ScanSummary> scan = new List<ScanSummary>();
scan = obj.GetAllScanSummaryData();
ScanSummary[] array = scan.ToArray();
mRemoverecyclerholder = new List<Removerecyclerholder>();
for (int i = 0; i < array.Length; i++)
{
mRemoverecyclerholder.Add(new Removerecyclerholder() { partnumber_r = scan[i].SSPartNo, containernumber_r = scan[i].SSContainerSN, scanquantity_r = scan[i].SSPackType, totalquantity_r = scan[i].SSStatus });
}
mRecyclerView_remove = FindViewById<RecyclerView>(Resource.Id.recyclerview_remove);
mLayoutManager_remove = new LinearLayoutManager(this);
mRecyclerView_remove.SetLayoutManager(mLayoutManager_remove);
mAdapter_remove = new RecyclerAdapter_remove(mRemoverecyclerholder);
mRecyclerView_remove.SetAdapter(mAdapter_remove);
}
}
public class RecyclerAdapter_remove : RecyclerView.Adapter
{
private List<Removerecyclerholder> mRemoverecyclerholder;
public RecyclerAdapter_remove(List<Removerecyclerholder> removerecyclerholder)
{
mRemoverecyclerholder = removerecyclerholder;
}
public class MyView : RecyclerView.ViewHolder
{
public View mMainView { get; set; }
public TextView mpartnumber_r { get; set; }
public TextView mcontainernumber_r { get; set; }
public TextView mtotalquantity_r { get; set; }
public TextView mscanquantity_r { get; set; }
public MyView(View view) : base(view)
{
mMainView = view;
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
SQLiteDb obj = new SQLiteDb();
List<ScanSummary> scan = obj.GetAllScanSummaryData();
View RemoveRecycleLayout = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.RemoveAlertRecycleLayout, parent, false);
TextView txtpartnumber_r = RemoveRecycleLayout.FindViewById<TextView>(Resource.Id.partnumber_remove);
TextView txtcontainernumber_r = RemoveRecycleLayout.FindViewById<TextView>(Resource.Id.containernumber_remove);
TextView txttotalquantity_r = RemoveRecycleLayout.FindViewById<TextView>(Resource.Id.totalquantity_remove);
TextView txtscanquantity_r = RemoveRecycleLayout.FindViewById<TextView>(Resource.Id.scanquantity_remove);
MyView view = new MyView(RemoveRecycleLayout) { mpartnumber_r = txtpartnumber_r, mcontainernumber_r = txtcontainernumber_r, mtotalquantity_r = txttotalquantity_r, mscanquantity_r = txtscanquantity_r };
return view;
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
MyView myholder = holder as MyView;
myholder.mpartnumber_r.Text = mRemoverecyclerholder[position].partnumber_r;
myholder.mcontainernumber_r.Text = mRemoverecyclerholder[position].containernumber_r;
myholder.mtotalquantity_r.Text = mRemoverecyclerholder[position].totalquantity_r;
myholder.mscanquantity_r.Text = mRemoverecyclerholder[position].scanquantity_r;
((MyView)holder).mMainView.Click += delegate (object sender, EventArgs e)
{
View mMainView = (View)sender;
mMainView.SetBackgroundColor(color: Color.Blue);
var activity = new Intent(Application.Context, typeof(RemoveDataDetails));
activity.PutExtra("partnumber_r", mRemoverecyclerholder[position].partnumber_r);
activity.PutExtra("containernumber_r", mRemoverecyclerholder[position].containernumber_r);
Application.Context.StartActivity(activity);
};
}
public override int ItemCount
{
get { return mRemoverecyclerholder.Count; }
}
}
How to show date or today , yesterday like text in between conversation
like whatsapp
MainActivity
public class MainActivity extends AppCompatActivity {
private ChatAdapter chatAdapter;
private RecyclerView recyclerView;
private Context context;
private int loggedInUserID;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindRecyclerView();
// TODO get logged in user id and initialize into 'loggedInUserID'
}
#Override
protected void onResume() {
super.onResume();
getData();
}
private void getData() {
/**
*Your server call to get data and parse json to your appropriate model
* after parsing json to model simply call the
*/
List<ChatModel> chatModelList = ParseData.chatParser(jsonArray);
groupDataIntoHashMap(chatModelList);
}
private void bindRecyclerView() {
chatAdapter = new ChatAdapter(null);
chatAdapter.setUser(loggedInUserID);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(chatAdapter);
}
private void groupDataIntoHashMap(List<ChatModel> chatModelList) {
LinkedHashMap<String, Set<ChatModel>> groupedHashMap = new LinkedHashMap<>();
Set<ChatModel> list = null;
for (ChatModel chatModel : chatModelList) {
//Log.d(TAG, travelActivityDTO.toString());
String hashMapKey = DateParser.convertDateToString(chatModel.getChatTime());
//Log.d(TAG, "start date: " + DateParser.convertDateToString(travelActivityDTO.getStartDate()));
if (groupedHashMap.containsKey(hashMapKey)) {
// The key is already in the HashMap; add the pojo object
// against the existing key.
groupedHashMap.get(hashMapKey).add(chatModel);
} else {
// The key is not there in the HashMap; create a new key-value pair
list = new LinkedHashSet<>();
list.add(chatModel);
groupedHashMap.put(hashMapKey, list);
}
}
//Generate list from map
generateListFromMap(groupedHashMap);
}
private List<ListObject> generateListFromMap(LinkedHashMap<String, Set<ChatModel>> groupedHashMap) {
// We linearly add every item into the consolidatedList.
List<ListObject> consolidatedList = new ArrayList<>();
for (String date : groupedHashMap.keySet()) {
DateObject dateItem = new DateObject();
dateItem.setDate(date);
consolidatedList.add(dateItem);
for (ChatModel chatModel : groupedHashMap.get(date)) {
ChatModelObject generalItem = new ChatModelObject();
generalItem.setChatModel(chatModel);
consolidatedList.add(generalItem);
}
}
chatAdapter.setDataChange(consolidatedList);
return consolidatedList;
}
}
ChatModel.java
public class ChatModel implements Serializable {
private String messageId;
private int userId;
private String firstName;
private String userName;
private String message;
private Date chatTime;
//TODO generate getter and setter
}
ListObject.java (to determind the type of message)
public abstract class ListObject {
public static final int TYPE_DATE = 0;
public static final int TYPE_GENERAL_RIGHT = 1;
public static final int TYPE_GENERAL_LEFT = 2;
abstract public int getType(int userId);
}
DateObject.java
public class DateObject extends ListObject {
private String date;
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
#Override
public int getType(int userId) {
return TYPE_DATE;
}
}
ChatModelObject.java
public class ChatModelObject extends ListObject {
private ChatModel chatModel;
public ChatModel getChatModel() {
return chatModel;
}
public void setChatModel(ChatModel chatModel) {
this.chatModel = chatModel;
}
#Override
public int getType(int userId) {
if (this.chatModel.getUserId() == userId) {
return TYPE_GENERAL_RIGHT;
} else
return TYPE_GENERAL_LEFT;
}
}
DateParse.java to parse date for grouping the chat
public class DateParser {
private static DateFormat dateFormat1 = new SimpleDateFormat("dd/MM/yyyy");
public static String convertDateToString(Date date) {
String strDate = "";
strDate = dateFormat1.format(date);
return strDate;
}
}
ChatAdapter.java
public class ChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<ListObject> listObjects;
private int loggedInUserId;
public ChatAdapter(List<ListObject> listObjects) {
this.listObjects = listObjects;
}
public void setUser(int userId) {
this.loggedInUserId = userId;
}
public void setDataChange(List<ListObject> asList) {
this.listObjects = asList;
//now, tell the adapter about the update
notifyDataSetChanged();
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case ListObject.TYPE_GENERAL_RIGHT:
View currentUserView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_chat_list_row_right, parent, false);
viewHolder = new ChatRightViewHolder(currentUserView); // view holder for normal items
break;
case ListObject.TYPE_GENERAL_LEFT:
View otherUserView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_chat_list_row_left, parent, false);
viewHolder = new ChatLeftViewHolder(otherUserView); // view holder for normal items
break;
case ListObject.TYPE_DATE:
View v2 = inflater.inflate(R.layout.date_row, parent, false);
viewHolder = new DateViewHolder(v2);
break;
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
switch (viewHolder.getItemViewType()) {
case ListObject.TYPE_GENERAL_RIGHT:
ChatModelObject generalItem = (ChatModelObject) listObjects.get(position);
ChatRightViewHolder chatViewHolder = (ChatRightViewHolder) viewHolder;
chatViewHolder.bind(generalItem.getChatModel());
break;
case ListObject.TYPE_GENERAL_LEFT:
ChatModelObject generalItemLeft = (ChatModelObject) listObjects.get(position);
ChatLeftViewHolder chatLeftViewHolder = (ChatLeftViewHolder) viewHolder;
chatLeftViewHolder.bind(generalItemLeft.getChatModel());
break;
case ListObject.TYPE_DATE:
DateObject dateItem = (DateObject) listObjects.get(position);
DateViewHolder dateViewHolder = (DateViewHolder) viewHolder;
dateViewHolder.bind(dateItem.getDate());
break;
}
}
#Override
public int getItemCount() {
if (listObjects != null) {
return listObjects.size();
}
return 0;
}
#Override
public int getItemViewType(int position) {
return listObjects.get(position).getType(loggedInUserId);
}
public ListObject getItem(int position) {
return listObjects.get(position);
}
}
ChatRightViewHolder.java for current user message
public class ChatRightViewHolder extends RecyclerView.ViewHolder {
private final String TAG = ChatRightViewHolder.class.getSimpleName();
public ChatRightViewHolder(View itemView) {
super(itemView);
//TODO initialize your xml views
}
public void bind(final ChatModel chatModel) {
//TODO set data to xml view via textivew.setText();
}
}
ChatLeftViewHolder.java for display other user messages.
public class ChatLeftViewHolder extends RecyclerView.ViewHolder {
private final String TAG = ChatRightViewHolder.class.getSimpleName();
public ChatLeftViewHolder(View itemView) {
super(itemView);
//TODO initialize your xml views
}
public void bind(final ChatModel chatModel) {
//TODO set data to xml view via textivew.setText();
}
}
DateViewHolder.java to display date
public class DateViewHolder extends RecyclerView.ViewHolder {
public DateViewHolder(View itemView) {
super(itemView);
//TODO initialize your xml views
}
public void bind(final String date) {
//TODO set data to xml view via textivew.setText();
}
}
You need to create a new ViewHolder for that purpose
For example:
// Different types of rows
private static final int TYPE_ITEM_LEFT = 0;
private static final int TYPE_ITEM_RIGHT = 1;
private static final int TYPE_ITEM_DATE_CONTAINER = 2;
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
class ViewHolder0 extends RecyclerView.ViewHolder {
// Viewholder for row type 0
}
class ViewHolder1 extends RecyclerView.ViewHolder {
// Viewholder for row type 1
}
class ViewHolder2 extends RecyclerView.ViewHolder {
// Viewholder for row type 2
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder.getItemViewType() == TYPE_ITEM_LEFT) {
// Code to populate type 0 view here
} else if (viewHolder.getItemViewType() == TYPE_ITEM_RIGHT) {
// Code to populate type 1 view here
} else if (viewHolder.getItemViewType() == TYPE_ITEM_DATE_CONTAINER) {
// Code to populate type 2 view here
}
}
You just have to compare the date when scrolling and set the visibility of date view. The advantage of this is there's no hard-coded today/yesterday in data list and is able to refresh the correct date immediately (scrolling) after 12.00 a.m.
e.g. in your onBindViewHolder() in recycleview:
if (position != 0) {
processDate(holder.topDateTextView, myData.getDate()
, this.myDataList.get(position - 1).getDate()
, false)
;
} else {
processDate(holder.topDateTextView, data.getDay()
, null
, true)
;
}
Method to process that date view (Assume your list has format "dd/MM/yyyy"):
private void processDate(#NonNull TextView tv, String dateAPIStr
, String dateAPICompareStr
, boolean isFirstItem) {
SimpleDateFormat f = new SimpleDateFormat("dd/MM/yyyy");
if (isFirstItem) {
//first item always got date/today to shows
//and overkill to compare with next item flow
Date dateFromAPI = null;
try {
dateFromAPI = f.parse(dateAPIStr);
if (DateUtils.isToday(dateFromAPI.getTime())) tv.setText("today");
else if (DateUtils.isToday(dateFromAPI.getTime() + DateUtils.DAY_IN_MILLIS)) tv.setText("yesterday");
else tv.setText(dateAPIStr);
tv.setIncludeFontPadding(false);
tv.setVisibility(View.VISIBLE);
} catch (ParseException e) {
e.printStackTrace();
tv.setVisibility(View.GONE);
}
} else {
if (!dateAPIStr.equalsIgnoreCase(dateAPICompareStr)) {
try {
Date dateFromAPI = f.parse(dateAPIStr);
if (DateUtils.isToday(dateFromAPI.getTime())) tv.setText("today");
else if (DateUtils.isToday(dateFromAPI.getTime() + DateUtils.DAY_IN_MILLIS)) tv.setText("yesterday");
else tv.setText(dateAPIStr);
tv.setIncludeFontPadding(false);
tv.setVisibility(View.VISIBLE);
} catch (ParseException e) {
e.printStackTrace();
tv.setVisibility(View.GONE);
}
} else {
tv.setVisibility(View.GONE);
}
}
}
Note: You also need to do yourAdapter.notifyDataSetChanged(); if append new item to redraw to dismiss previous "today"/date after 12.00 a.m on the same page, not just rely on yourAdapter.notifyItemInserted(new_item_position) which doesn't redraw previous items.
I am running into an issue where I use 2 separate adapters, and 2 seperate GridViews (1 Adapter, for 1 GridView), and am basically removing items from either adapter, and adding it to the other if the item is pressed, and vice versa.
When I press and item in one GridView, the item will be removed from its respective adapter and put into the other GridView and its respective adapter. The issue seems to be with the way the data is being stored (potentially) because when I add the item to the adapter, the icons are totally different from what they should be.
Note: I also noticed that this only happens for the items pressed after the first one is pressed. So the first items data will be added/removed properly. However, I have found that when the item that takes on the first position of the associated adapter, will now have the icon of the previously removed item.
What can I do so ensure that the data stays consistent with the item that is pressed?.
Adapter Class
public class MiscChargeOptionsAdapter extends ArrayAdapter<CarClassSettingDetails> {
private LayoutInflater inflater;
public MiscChargeOptionsAdapter(Context context, List<CarClassSettingDetails> settingList) {
super(context, R.layout.misc_charge_option_layout, R.id.option_grid_option_text, settingList);
inflater = LayoutInflater.from(context);
}
#SuppressLint("InflateParams")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
CarClassSettingDetails settingsDetails = this.getItem(position);
ViewHolder vh;
if (convertView == null) {
vh = new ViewHolder();
convertView = inflater.inflate(R.layout.misc_charge_option_layout, null);
vh.optionText = (TextView) convertView.findViewById(R.id.option_grid_option_text);
vh.settingView = (SettingView) convertView.findViewById(R.id.option_grid_option_icon);
convertView.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
vh.optionText.setText(settingsDetails.getName());
vh.settingView.setIcon(settingsDetails.getIcon());
vh.settingView.setIconSelected(settingsDetails.getIconSelected());
vh.settingView.setViewBackgroundColor(settingsDetails.getViewBackgroundColor());
vh.settingView.setBackgroundColorSelected(settingsDetails.getBackgroundColorSelected());
vh.settingView.setAmountBackgroundColor(settingsDetails.getAmountBackgroundColor());
vh.settingView.setAmountTextColor(settingsDetails.getAmountTextColor());
vh.settingView.setValue(settingsDetails.getValue());
vh.settingView.setIgnoreSetState(true);
vh.settingView.setTag(position);
return convertView;
}
class ViewHolder {
private TextView optionText;
private SettingView settingView;
/* public ViewHolder(TextView optionText, SettingView settingView) {
this.optionText = optionText;
this.settingView = settingView;
}*/
public TextView getOptionText() {
return optionText;
}
public SettingView getSettingView() {
return settingView;
}
}
}
How the adapters are set
selectedAdapter = new CarClassOptionsAdapter(getActivity(), selectedSettingsList);
unselectedAdapter = new CarClassOptionsAdapter(getActivity(), unselectedSettingsList);
gridSelected.setAdapter(selectedAdapter);
gridSelected.setOnItemClickListener(this);
gridUnselected.setAdapter(unselectedAdapter);
gridUnselected.setOnItemClickListener(this);
How I am adding/removing items from the adapters
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (parent.getAdapter() == selectedAdapter) {
//TODO: ADD DIALOGS
unselectedAdapter.add(selectedAdapter.getItem(position));
unselectedAdapter.notifyDataSetChanged();
selectedAdapter.remove(selectedAdapter.getItem(position));
selectedAdapter.notifyDataSetChanged();
} else if (parent.getAdapter() == unselectedAdapter) {
//TODO: ADD DIALOGS
selectedAdapter.add(unselectedAdapter.getItem(position));
selectedAdapter.notifyDataSetChanged();
unselectedAdapter.remove(unselectedAdapter.getItem(position));
unselectedAdapter.notifyDataSetChanged();
}
}
This is how the CarClassSettingDetails class is being populated
private void addMiscChargeSelected(Ws_MiscChargeSelected miscChargeSelected, boolean isSelected) {
try {
CarClassSettingDetails settingDetails = new CarClassSettingDetails(getActivity());
if (miscChargeSelected.getCode() != null && !miscChargeSelected.getCode().equals("")) {
settingDetails.setCode(miscChargeSelected.getCode());
}
if (miscChargeSelected.getName() != null && !miscChargeSelected.getName().equals("")) {
settingDetails.setName(miscChargeSelected.getName());
}
if (miscChargeSelected.getIcon() != null && !miscChargeSelected.getIcon().equals("")) {
Bitmap settingIcon = IconUtils.loadIcon(getActivity(), miscChargeSelected.getIcon());
Bitmap settingIconSelected = IconUtils.loadIcon(getActivity(), miscChargeSelected.getIcon());
settingDetails.setIcon(settingIcon);
settingDetails.setIconSelected(settingIconSelected);
}
if (miscChargeSelected.getValue() != null && !miscChargeSelected.getValue().equals("")) {
settingDetails.setValue(Ws_Value.fromInt(Integer.parseInt(miscChargeSelected.getValue())));
settingDetails.setAmountBackgroundColor(Color.parseColor("#00ffffff"));
settingDetails.setAmountTextColor(Color.parseColor("#ff00428e"));
} else {
settingDetails.setValue(null);
}
settingDetails.setViewBackgroundColor(Color.parseColor("#ffd4d4d4"));
settingDetails.setBackgroundColorSelected(Color.parseColor("#ff616161"));
if (isSelected) {
//TODO: ADD TO TOP ADAPTER
selectedSettingsList.add(settingDetails);
} else {
//TODO: ADD TO BOTTOM ADAPTER
unselectedSettingsList.add(settingDetails);
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
Misc Charge Details
public class MiscChargeSettingDetails {
private Context context;
private String code;
private String name;
private String description;
private Bitmap icon = null;
private Bitmap iconSelected = null;
private Ws_Value value = null;
private int amountBackgroundColor, amountTextColor, viewBackgroundColor, backgroundColorSelected;
public MiscChargeSettingDetails(Context context) {
this.context = context;
}
protected Context getContext() {
return context;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Bitmap getIcon() {
return icon;
}
public void setIcon(Bitmap icon) {
this.icon = icon;
}
public Bitmap getIconSelected() {
return iconSelected;
}
public void setIconSelected(Bitmap iconSelected) {
this.iconSelected = iconSelected;
}
public Ws_Value getValue() {
return value;
}
public void setValue(Ws_Value value) {
this.value = value;
}
public int getAmountBackgroundColor() {
return amountBackgroundColor;
}
public void setAmountBackgroundColor(int amountBackgroundColor) {
this.amountBackgroundColor = amountBackgroundColor;
}
public int getAmountTextColor() {
return amountTextColor;
}
public void setAmountTextColor(int amountTextColor) {
this.amountTextColor = amountTextColor;
}
public int getViewBackgroundColor() {
return viewBackgroundColor;
}
public void setViewBackgroundColor(int viewBackgroundColor) {
this.viewBackgroundColor = viewBackgroundColor;
}
public int getBackgroundColorSelected() {
return backgroundColorSelected;
}
public void setBackgroundColorSelected(int backgroundColorSelected) {
this.backgroundColorSelected = backgroundColorSelected;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
Can you show the place where you're populating the list of SettingViews? Is your data model (SettingView) extends View? It is not the best idea to use the view object as model..
In the code below I have a ListView with a Items list containing Name, Id and Quantity. When I click on a row this value should be updated according to informed parameter in UpdateItemSelectedInListView () method. But only line 9 is having the changed value, independent of the line that I select.
Activity:
public class MainActivity : Activity
{
ListView _ListView;
AdapterItem _Adapter;
List<Item> _ListaItem = new List<Item>();
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
CriaListView();
}
private void CriaListView()
{
_ListView = FindViewById<ListView>(Resource.Id.listaItems);
_ListView.ItemClick += _ListView_ItemClick;
_ListView.Adapter = CriaAdapter();
}
private AdapterItem CriaAdapter()
{
for (int i = 0; i < 15; i++)
{
_ListaItem.Add(new Item("Test Name",i));
}
_Adapter = new AdapterItem(this, _ListaItem);
return _Adapter;
}
void _ListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
_Adapter.UpdateItemSelectedInListView(e.Position, 5);
}
}
Adapter:
public class AdapterItem : BaseAdapter
{
List<Item> _ListaItem = new List<Item>();
Activity _Activity;
LayoutInflater _Inflate;
ViewHolderItem _HolderItem;
Boolean _HasUpdate;
int _IdToUpDate;
int _NewQntd;
int _Position;
public AdapterItem(Activity activity, List<Item> listaItem)
{
_Activity = activity;
_ListaItem = listaItem;
try
{
_Inflate = (LayoutInflater)_Activity.GetSystemService(Context.LayoutInflaterService);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
View _View;
public override View GetView(int position, Android.Views.View convertView, Android.Views.ViewGroup parent)
{
_View = convertView;
try
{
if (_View != null)
_HolderItem = _View.Tag as ViewHolderItem;
else
{
_View = _Activity.LayoutInflater.Inflate(Resource.Layout.LayoutItem, null);
_HolderItem = CriaViewHolder();
}
PopulaViewHolder(position);
_View.Tag = _HolderItem;
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return _View;
}
private ViewHolderItem CriaViewHolder()
{
ViewHolderItem holderItem = new ViewHolderItem();
holderItem.txtNameItem = _View.FindViewById<TextView>(Resource.Id.nameItem);
holderItem.txtIdItem = _View.FindViewById<TextView>(Resource.Id.idItem);
holderItem.txtqntItem = _View.FindViewById<TextView>(Resource.Id.totalInStock);
return holderItem;
}
private void PopulaViewHolder(int position)
{
_HolderItem.txtNameItem.Text = _ListaItem[position].nome;
_HolderItem.txtIdItem.Text = _ListaItem[position].id.ToString();
if (_HasUpdate && (position == _Position))
UpdateAdapter();
}
public void UpdateAdapter()
{
_HolderItem.txtqntItem.Text = _NewQntd.ToString();
_HasUpdate = false;
}
public void UpdateItemSelectedInListView(int position, int newValue)
{
_NewQntd = newValue;
_HasUpdate = true;
_Position = position;
this.NotifyDataSetChanged();
}
public override Java.Lang.Object GetItem(int position)
{
return 0;
}
public override int Count
{
get {return _ListaItem.Count; }
}
public override long GetItemId(int position)
{
return _ListaItem[position].id;
}
public override int GetItemViewType(int position)
{
return base.GetItemViewType(position);
}
public override int ViewTypeCount
{
get
{
return base.ViewTypeCount;
}
}
private class ViewHolderItem : Java.Lang.Object
{
public TextView txtNameItem { get; set; }
public TextView txtIdItem { get; set; }
public TextView txtqntItem { get; set; }
}
}
You need to move _View.Tag = _HolderItem; inside of the else on the GetView method:
public override View GetView(int position, Android.Views.View convertView, Android.Views.ViewGroup parent)
{
_View = convertView;
try
{
if (_View != null)
_HolderItem = _View.Tag as ViewHolderItem;
else
{
_View = _Activity.LayoutInflater.Inflate(Resource.Layout.LayoutItem, null);
_HolderItem = CriaViewHolder();
//Set the tag only when you create a new one
//otherwise you'll have the problem you are having
_View.Tag = _HolderItem;
}
PopulaViewHolder(position);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return _View;
}
It seems that your _Adapter.UpdateItemSelectedInListView not fetching correct position as it looses the state. Instead you can make use of binding "event action" to each view row from viewholder class.
On trigger of this action event [ in GetView()] another event action to activity class to process Click event.
//Viewholder class
internal Action ActionImgViewSelectedToGetView{ get; set;}
internal void Initialize(View view)
{
imgItem=view.FindViewById<ImageView> (Resource.Id.imgItem);
imgItem.Click += delegate(object sender , EventArgs e )
{
ActionImgViewSelectedToGetView(); //action event to getview()
};
}
//in getview()
viewHolder.ActionImgViewSelectedToGetView = () =>
{
if(ActionImgSelectedToActivity!=null)
ActionImgSelectedToActivity(_lstItem[position].ItemName); //action event,targeting to activity class method
};
//activity
if ( objItemAdapter != null )
{
objItemAdapter.ActionImgSelectedToActivity -= SelectedItem;
objItemAdapter = null;
}
objItemAdapter = new ItemAdapterClass (this, lstItem);
objItemAdapter.ActionImgSelectedToActivity += SelectedItem;
listViewItem.Adapter = objItemAdapter;
void SelectedItem( string strItemName)
{
//seleced item
}
for more detail : http://appliedcodelog.blogspot.in/2015/07/working-on-issues-with-listview-in.html#WrongPosition
I have a listview with a list of items. There is an event that sends the new value for a given row of the listview. For example: I have a listview with the names ("Jhon", "Alice", "Paul", "Mary", "Stive") then the event me "warns" that the name of Jhon was changed to "Josh". How can I access the online listview containing the name "Jhon", I am using adapter and viewholder to populate the listview.
using System;
using Android.App;
using Android.Views;
using Android.Widget;
using MyApp
using Android.Content;
using System.Collections.Generic;
using Android.Graphics;
public class AdapterContatos : BaseAdapter
{
private Activity _Activity = null;
private static Usuario[] _ListaContatos;
private static Grupo[] _Listagrupos;
private static List<Object> _ListaCompleta = new List<object>();
private static LayoutInflater _Inflate = null;
private static View _View;
private static Dictionary<int, Bitmap> _DicAvatarContato = new Dictionary<int, Bitmap>();
private static Dictionary<int, Bitmap> _DicAvatarGrupo = new Dictionary<int, Bitmap>();
public AdapterContatos(Activity activity, Usuario[] listaContatos, Grupo[] listaGrupo)
{
_Activity = activity;
_ListaContatos = listaContatos;
_Listagrupos = listaGrupo;
_ListaCompleta.AddRange(_Listagrupos);
_ListaCompleta.AddRange(_ListaContatos);
try
{
_Inflate = (LayoutInflater)_Activity.GetSystemService(Context.LayoutInflaterService);
foreach (var item in _ListaContatos)
ObtemImagemArredondadaContato(item.Codigo);
foreach (var item in _Listagrupos)
ObtemImagemArredondadaGrupo(item.CodigoDoGrupo);
}
catch (Exception ex)
{
UtilExcessao.TrateExcessao(ex);
}
}
ViewHolderContato _HolderContato;
public override View GetView(int position, View convertView, ViewGroup parent)
{
_View = convertView;
try
{
if (_View != null)
_HolderContato = _View.Tag as ViewHolderContato;
else
{
_View = _Activity.LayoutInflater.Inflate(Resource.Layout.LayoutContato, null);
_HolderContato = CriaViewHolder(position);
}
PopulaViewHolder(_HolderContato, position);
_View.Tag = _HolderContato;
}
catch (Exception ex)
{
UtilExcessao.TrateExcessao(ex);
}
return _View;
}
private ViewHolderContato CriaViewHolder(int position)
{
ViewHolderContato holder = new ViewHolderContato();
holder.txtNome = _View.FindViewById<TextView>(Resource.Id.nomeContato);
holder.txtCargo = _View.FindViewById<TextView>(Resource.Id.funcaoContato);
holder.imgAvatar = _View.FindViewById<ImageView>(Resource.Id.imgAvatar);
holder.txtPrimeiraLetraNomeOuGrupo = _View.FindViewById<TextView>(Resource.Id.txtPrimeiraLetraNomeOuGrupo);
holder.txtQntdMsgNaoLidas = _View.FindViewById<TextView>(Resource.Id.imgAlertaChat);
return holder;
}
private void PopulaViewHolder(ViewHolderContato holder, int position)
{
if(EhGrupo(_ListaCompleta[position]))
PopulaViewHolderGrupo(holder,
(Grupo)_ListaCompleta[position]);
else
PopulaViewHolderUsuario(holder,
(Usuario)_ListaCompleta[position]);
}
void PopulaViewHolderGrupo(ViewHolderContato holder, Grupo grupo)
{
holder.txtNome.Text = grupo.NomeDoGrupo;
holder.txtCargo.Text = UtilFormatacao.ObtenhaNomeIntegrantesGrupoFormatado(grupo.ListaDeUsuarios);
holder.txtPrimeiraLetraNomeOuGrupo.Text = UtilFormatacao.ObtenhaPrimeiraLetraDoNome(grupo.NomeDoGrupo);
MostraAvatargrupo(holder, grupo.CodigoDoGrupo, grupo.NomeDoGrupo);
}
void PopulaViewHolderUsuario(ViewHolderContato holder, Usuario usuario)
{
holder.txtNome.Text = usuario.Nome;
holder.txtCargo.Text = usuario.Cargo;
MostraAvatarContatoPrivado(holder, usuario.Codigo, usuario.Nome);
}
void MostraAvatarContatoPrivado(ViewHolderContato holder, int codigo, string nome)
{
if (_DicAvatarContato[codigo] != null)
{
holder.imgAvatar.SetImageBitmap(_DicAvatarContato[codigo]);
holder.txtPrimeiraLetraNomeOuGrupo.Text = "";
}
else
{
holder.imgAvatar.SetImageResource(Resource.Drawable.icon_avatar_default_52);
holder.txtPrimeiraLetraNomeOuGrupo.Text = UtilFormatacao.ObtenhaPrimeiraLetraDoNome(nome);
}
}
void MostraAvatargrupo(ViewHolderContato holder, int codigoGrupo, string nomeGrupo)
{
if (_DicAvatarGrupo[codigoGrupo] != null)
{
holder.imgAvatar.SetImageBitmap(_DicAvatarGrupo[codigoGrupo]);
holder.txtPrimeiraLetraNomeOuGrupo.Text = "";
}
else
{
holder.imgAvatar.SetImageResource(Resource.Drawable.icon_avatar_default_52);
holder.txtPrimeiraLetraNomeOuGrupo.Text = UtilFormatacao.ObtenhaPrimeiraLetraDoNome(nomeGrupo);
}
}
private void ObtemImagemArredondadaContato(int codigo)
{
using (var bmp = UtilImagem.ObtemImagemArredondado(UtilImagem.ObtemImagemLocalContato(codigo), 60, 80, 80))
{
_DicAvatarContato.Add(codigo, bmp);
}
}
private void ObtemImagemArredondadaGrupo(int codigoGrupo)
{
using (var bmp = UtilImagem.ObtemImagemArredondado(UtilImagem.ObtemImagemLocalGrupo(codigoGrupo), 60, 80, 80))
{
_DicAvatarGrupo.Add(codigoGrupo, bmp);
}
}
public bool EhGrupo(Object objeto)
{
return object.Equals(objeto.GetType(),
typeof(Grupo));
}
private int ObtenhaCodigoGrupoOuUsuario(int position)
{
if (EhGrupo(_ListaCompleta[position]))
{
Grupo G = (Grupo)_ListaCompleta[position];
return G.CodigoDoGrupo;
}
else
{
Usuario U = (Usuario)_ListaCompleta[position];
return U.Codigo;
}
}
public void AdicionaNovoContato(Usuario usario)
{
}
public void RemoveContato(Usuario usuario)
{
}
public void AdicionaNovoGrupo(Grupo grupo)
{
}
public void RemoveGrupo(Grupo grupo)
{
}
public override int GetItemViewType(int position)
{
return base.GetItemViewType(position);
}
public int GetCount()
{
return _ListaCompleta.Count;
}
public override Java.Lang.Object GetItem(int position)
{
return ObtenhaCodigoGrupoOuUsuario(position);
}
public Object ObtenhaTipoObjeto(int position)
{
return _ListaCompleta[position];
}
public Grupo ObtenhaGrupoDaLista(int codigo)
{
foreach (var item in _Listagrupos)
{
if (item.CodigoDoGrupo == codigo)
return item;
}
return null;
}
public override long GetItemId(int position)
{
return ObtenhaCodigoGrupoOuUsuario(position);
}
public override int Count
{
get { return _ListaCompleta.Count; }
}
private class ViewHolderContato : Java.Lang.Object
{
public TextView txtNome { get; set; }
public TextView txtCargo { get; set; }
public TextView txtPrimeiraLetraNomeOuGrupo { get; set; }
public ImageView imgAvatar { get; set; }
}
}
Simply call notifyDataSetChanged on your Adapter. This will inform it that the data inside the ListView has changed.
More info here: http://developer.android.com/reference/android/widget/BaseAdapter.html#notifyDataSetChanged()