I have a very strange problem while using my ListView.
Only a part of my adapter items are renderd in the listview on screen but when I interact with the listview (ie tries to scroll it) all items are renderd properly.
This fenonemon only occurs if i have less items than the screen can show. Take a look at these screenshots below.
Before interaction:
After interaction:
Source code of activity where adding items:
String[] jRests = getResources().getStringArray(R.array.j_restaurants);
String[] lRests = getResources().getStringArray(R.array.l_restaurants);
items = new ArrayList<Object>();
items.add(getString(R.string.campus_j));
for(String item : jRests){
String[] val = item.split(",,,");
items.add(new FoodSectionListItem(new Restaurant(val[0], val[1], val[2], "")));
}
items.add(getString(R.string.campus_l));
for(String item : lRests){
String[] val = item.split(",,,");
items.add(new FoodSectionListItem(new Restaurant(val[0], val[1], val[2], "")));
}
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
adapter = new BaseSectionAdapter(this, R.layout.list_item_fragment_header);
if(!isTabletView()){
adapter.setSelectedItem(-1);
}
adapter.setItems(items);
Code of adapter:
public class BaseSectionAdapter extends AmazingAdapter {
private LayoutInflater inflater;
private int selectedItem = 0;
private List<Object> items;
private List<SectionItem> sections = new ArrayList<SectionItem>(10);
private List<Class> itemTypes = new ArrayList<Class>();
private List<Integer> sectionPositions = new ArrayList<Integer>();
private int listHeaderLayoutId;
private View headerView;
public static interface ISectionListItem {
public void setProps(View convertView, int position, int selectedItem);
public View getLayout(LayoutInflater inflater);
}
private class SectionItem implements Serializable {
private static final long serialVersionUID = -8930010937740160935L;
String text;
int position;
public SectionItem(String text, int position) {
this.text = text;
this.position = position;
}
}
public BaseSectionAdapter(Context context, int listHeaderLayoutId) {
this.listHeaderLayoutId = listHeaderLayoutId;
init(context);
}
public BaseSectionAdapter(Context context, int listHeaderLayoutId, List<Object> listItems) {
this.listHeaderLayoutId = listHeaderLayoutId;
init(context);
initListItems(listItems);
}
private void init(Context context) {
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void setSelectedItem(int position) {
selectedItem = position;
}
// public List<ListItem> getItems() {
// return items;
// }
private void initListItems(List<Object> itemList) {
int curSection = -1;
//int curPosition = 0;
//curSection = 0;
this.items = itemList;
itemTypes.clear();
sections.clear();
sectionPositions.clear();
int listSize = itemList.size();
for(int i = 0; i < listSize; i++){
Object currentItem = items.get(i);
if(currentItem instanceof String){
sections.add(new SectionItem((String) currentItem,i));
curSection++;
}
if(!itemTypes.contains(currentItem.getClass())){
itemTypes.add(currentItem.getClass());
}
sectionPositions.add(curSection);
}
Log.d("test", "No of items = "+items.size());
Log.d("test", "No of itemtypes = "+itemTypes.size());
Log.d("test", "View type count = "+getViewTypeCount());
}
public void setItems(List<Object> itemList) {
initListItems(itemList);
}
public int getCount() {
return items==null?0:items.size();
}
#Override
public int getViewTypeCount(){
return (itemTypes.size() == 0)?1:itemTypes.size();
}
#Override
public int getItemViewType(int position){
return itemTypes.indexOf(items.get(position).getClass());
}
#Override
public boolean isEnabled(int position){
return !(items.get(position) instanceof String || items.get(position) instanceof EmptySectionListItem);
}
#Override
public Object getItem(int position) {
return items.get(position);
}
public long getItemId(int position) {
return position;
}
#Override
protected void onNextPageRequested(int page) {
// TODO Auto-generated method stub
}
#Override
protected void bindSectionHeader(View view, int position,
boolean displaySectionHeader) {
// TextView lSectionTitle = (TextView) view
// .findViewById(R.id.txt_list_header);
// if (displaySectionHeader) {
// lSectionTitle.setVisibility(View.VISIBLE);
// lSectionTitle
// .setText(getSections()[getSectionForPosition(position)]);
// } else {
// lSectionTitle.setVisibility(View.GONE);
// }
}
#Override
public View getAmazingView(int position, View convertView, ViewGroup parent) {
Object curItemObject = items.get(position);
boolean isHeader = (curItemObject instanceof String);
if(convertView == null){
if(isHeader && headerView != null){
convertView = headerView;
}else if(isHeader){
convertView = inflater.inflate(listHeaderLayoutId, null);
headerView = convertView;
}else{
convertView = ((ISectionListItem) curItemObject).getLayout(inflater);
}
}
if(isHeader){
TextView header = ((TextView)convertView.findViewById(R.id.txt_list_header));
header.setText((String)curItemObject);
}else{
((ISectionListItem)curItemObject).setProps(convertView, position, selectedItem);
}
return convertView;
}
#Override
public void configurePinnedHeader(View header, int position, int alpha) {
TextView textView = ((TextView)header.findViewById(R.id.txt_list_header));
textView.setText(getSections()[getSectionForPosition(position)]);
}
#Override
public int getPositionForSection(int section) {
if(section >= sections.size()){
return 0;
}
return sections.get(section).position;
}
#Override
public int getSectionForPosition(int position) {
return sectionPositions.get(position);
}
#Override
public String[] getSections() {
String[] res = new String[sections.size()];
for (int i = 0; i < res.length; i++) {
res[i] = sections.get(i).text;
}
return res;
}
}
Code of layout:
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.HORIZONTAL);
FrameLayout listLayout = new FrameLayout(this);
LinearLayout.LayoutParams listParams = new LinearLayout.LayoutParams(0, FrameLayout.LayoutParams.MATCH_PARENT);
listParams.weight = 1;
listLayout.setId(LIST_FRAGMENT_VIEW_ID);
FrameLayout detailLayout = new FrameLayout(this);
LinearLayout.LayoutParams detailParams = new LinearLayout.LayoutParams(0, FrameLayout.LayoutParams.MATCH_PARENT);
detailParams.weight = 2;
detailLayout.setId(DETAIL_FRAGMENT_VIEW_ID);
layout.addView(listLayout, listParams);
layout.addView(detailLayout, detailParams);
if(savedInstanceState == null){
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(listLayout.getId(), (Fragment) listFragment, TWO_PANEL_LIST_FRAGMENT_TAG);
ft.add(detailLayout.getId(), detailFragment);
ft.commit();
}
setContentView(layout);
try calling notifyDataSetChanged() in runOnUIThread() method like I have shown below and it will work like a charm. :)
runOnUiThread(new Runnable() {
#Override
public void run() {
messageAdapter.notifyDataSetChanged();
}
});
i dont know what causes the problem, but if you don't find a logical solution to it you could try something like this:
trigger an onTouchEvent() programmatically whenever you launch the ListView.
scroll down and back up programmatically as soon as the ListView is launched.
etc..
Add ListView widget to layout.xml and add content of list to that. Do not use FrameLayout as it probably is the cause of the problem. It is updating content after touch so the Layout it is on is no implementing the correct onCreate() setup as the ListView widget has.
Are you calling the method notifyDataSetChanged() on your adapter after adding new items? This causes the listview to refresh its view when the underlying dataset is changed.
If it still doesn't work, try notifyDataSetInvalidated() that causes the listview to redraw completely.
Solved it!!!
Problem was with the adapter trying to reuse the same section item. Not good!!!
Changed it to inflate the section item each time we hit a section!
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!
So I have a listView that I'm populating with a static xml, but inside that xml I have a dynamic container that I inflate items into when the user clicks on an item in the listView.
Basically the view(s) I'm inflating looks like (x) amount of radio buttons and a textView.
The reason I have to do it this way is that the amount of radio buttons inflated could change depending on what type of list item it is.
The issue I'm running into is that once the radio buttons are inflated and the user selects a button, the list doesn't save the state from which the user last selected the radio button. Or rather, it recycles the radio button state to another position in the list. Which is somewhat correct since that's what listview does. I want it to only save the user selected answer at the position they selected in the listView.
I've been working on this for about a week and can't find a good solution. If anyone would like to help I'd greatly appreciate it. I'll post the relevant code below.
SurveyView (Custom container to inflate views into)
public class SurveyView extends LinearLayout {
private LinearLayout pollContainer;
private Context context;
private String type;
private int numOfAnswers;
private ListView answersList;
private ArrayList<String> answers;
private boolean visibility = true;
private OnClickListener listener;
private ArrayList<View> options;
private static int tag = 88888888;
private ArrayList<Boolean> checked;
private Integer[] percent = {33, 25, 15, 20, 7};
private int position;
/**
* #param context the context of the activity
* #param type the type of poll
* #param numOfAnswers if the poll is multiple choice (most likely) provide number of answers.
*/
public void setLayout(final Context context, String type, int numOfAnswers, final int position) {
this.type = type;
this.numOfAnswers = numOfAnswers;
this.context = context;
this.position = position;
switch (type) {
case "Multiple":
if (visibility) {
for (int i = 0; i < numOfAnswers; i++) {
View v = LayoutInflater.from(getContext()).inflate(R.layout.poll_multiple_choice_answers_row, null);
View space = LayoutInflater.from(getContext()).inflate(R.layout.space, null);
v.setTag(tag);
options.add(v);
final RadioButton rb = (RadioButton) v.findViewById(R.id.answer_voted_button);
rb.setClickable(false);
rb.setFocusable(false);
tag++;
addView(v);
addView(space);
}
}
break;
case "Slider":
break;
case "Tree":
break;
case "Sentiment":
break;
}
}
public SurveyView(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(VERTICAL);
options = new ArrayList<>();
}
public boolean isVisibility() {
return visibility;
}
public void setVisibility(boolean visibility) {
this.visibility = visibility;
}
public void setAnswers(int position) {
RadioButton rb;
for (int i = 0; i < options.size(); i++) {
if (i != position) {
rb = (RadioButton) options.get(i).findViewById(R.id.answer_voted_button);
rb.setChecked(false);
}
else {
rb = (RadioButton) options.get(position).findViewById(R.id.answer_voted_button);
rb.setChecked(true);
for (int p = 0; p < options.size(); p++) {
TextView answer = (TextView) options.get(p).findViewById(R.id.poll_answer);
answer.setText("Abraham Lincoln");
TextView tv = (TextView) options.get(p).findViewById(R.id.answer_percent);
tv.setText(Integer.toString(percent[p]));
options.get(p).setBackground(new PercentDrawable(percent[p], context.getResources().getColor(R.color.icitizen_poll_opaque_gold)));
}
}
}
}
Adapter for the listview
PollsAdapter extends BaseAdapter {
private LayoutInflater inflater;
private Context context;
private ArrayList<Card> data;
private ArrayList<RelativeLayout.LayoutParams> params;
private ArrayList<Integer> pollAnswers;
private int selectedPosition = 0;
public PollsAdapter(Context context, ArrayList<Card> data,
ArrayList<RelativeLayout.LayoutParams> params,
ArrayList<Integer> pollAnswers) {
this.context = context;
this.data = data;
inflater = LayoutInflater.from(context);
this.params = params;
this.pollAnswers = pollAnswers;
}
public static class ViewHolder {
TextView type;
TextView time;
TextView text;
TextView space;
TextView pollSpace;
ImageView type_icon;
SurveyView answerView;
RadioButton rb;
ArrayList<View> options;
private ViewHolder() {
}
private ViewHolder(TextView type, TextView time, TextView text, ImageView type_icon, SurveyView answerView) {
this.type = type;
this.time = time;
this.text = text;
this.type_icon = type_icon;
this.answerView = answerView;
}
public TextView getType() {
return type;
}
public void setType(TextView type) {
this.type = type;
}
public TextView getTime() {
return time;
}
public void setTime(TextView time) {
this.time = time;
}
public TextView getText() {
return text;
}
public void setText(TextView text) {
this.text = text;
}
public ImageView getType_icon() {
return type_icon;
}
public void setType_icon(ImageView type_icon) {
this.type_icon = type_icon;
}
public SurveyView getAnswerView() {
return answerView;
}
public void setAnswerView(SurveyView answerView) {
this.answerView = answerView;
}
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = inflater.inflate(R.layout.polls_card_layout, null);
viewHolder.type = (TextView)convertView.findViewById(R.id.card_type);
viewHolder.time = (TextView)convertView.findViewById(R.id.card_poll_time);
viewHolder.text = (TextView)convertView.findViewById(R.id.card_text);
viewHolder.space = (TextView)convertView.findViewById(R.id.card_space);
viewHolder.pollSpace = (TextView)convertView.findViewById(R.id.poll_space);
viewHolder.type_icon = (ImageView)convertView.findViewById(R.id.card_icon);
viewHolder.answerView = (SurveyView)convertView.findViewById(R.id.poll_component);
viewHolder.rb = (RadioButton)viewHolder.answerView.findViewById(R.id.answer_voted_button);
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder)convertView.getTag();
}
viewHolder.type.setText(data.get(position).getType());
viewHolder.time.setText(data.get(position).getTime());
viewHolder.text.setText(data.get(position).getText());
viewHolder.answerView.setLayoutParams(params.get(position));
viewHolder.answerView.setLayout(context, "Multiple", 5, position);
viewHolder.answerView.setVisibility(false);
viewHolder.answerView.setAnswers(pollAnswers.get(position));
return convertView;
}
The fragment for the listview
SurveyListFragment extends ListFragment {
private ArrayList<Card> cardList;
private PollsAdapter adapter;
private ArrayList<Answer> answers;
ArrayList<Integer> visible;
private ArrayList<RelativeLayout.LayoutParams> params;
private ArrayList<Integer> pollAnswers;
/**
when user clicks on a poll display the poll options for it
*/
#Override
public void onListItemClick(ListView l, View view, final int position, long id) {
final PollsAdapter.ViewHolder holder = (PollsAdapter.ViewHolder)adapter.getView(position, view, l).getTag();
if (holder.getAnswerView().getHeight() == 0) {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.BELOW, R.id.poll_space);
params.addRule(RelativeLayout.RIGHT_OF, R.id.card_icon);
//holder.getAnswerView().setLayoutParams(params);
this.params.set(position, params);
for (int i = 0; i < holder.getAnswerView().getOptions().size(); i++) {
holder.getAnswerView().getOptions().get(i).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for (int p = 0; p < holder.getAnswerView().getOptions().size(); p++) {
if (holder.getAnswerView().getOptions().get(p) == v) {
holder.getAnswerView().setAnswers(p);
pollAnswers.set(position, p);
adapter = new PollsAdapter(getActivity(), cardList, SurveyListFragment.this.params, pollAnswers);
setListAdapter(adapter);
}
}
}
});
}
}
else {
holder.getAnswerView().setVisibility(false);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, 0);
params.addRule(RelativeLayout.BELOW, R.id.poll_space);
params.addRule(RelativeLayout.RIGHT_OF, R.id.card_icon);
this.params.set(position, params);
// holder.getAnswerView().setLayoutParams(params);
adapter.notifyDataSetChanged();
}
super.onListItemClick(l, view, position, id);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setListAdapter(adapter);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
cardList = new ArrayList<>();
answers = new ArrayList<>();
visible = new ArrayList<>();
params = new ArrayList<>();
pollAnswers = new ArrayList<>();
Answer answer = new Answer();
answer.setText("one");
answers.add(answer);
answer = new Answer();
answer.setText("two");
answers.add(answer);
answer = new Answer();
answer.setText("three");
answers.add(answer);
answer = new Answer();
answer.setText("four");
answers.add(answer);
Card card = new Card();
card.setType("Polls");
card.setText("What issue listed below would you like to see as a priority for Nashville’s next mayor?");
card.setTime("Closing Soon");
for (int i = 0; i < cardList.size(); i++) {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, 0);
params.addRule(RelativeLayout.BELOW, R.id.poll_space);
params.addRule(RelativeLayout.RIGHT_OF, R.id.card_icon);
this.params.add(params);
pollAnswers.add(-1);
}
adapter = new PollsAdapter(getActivity(), cardList, params, pollAnswers);
}
Parse the survey object to the view class when you create the convertView. And parse a new object every time recycle previous views. Here are some codes.
1) Initialize the views in ProductListItemView
public ProductListItemView(Context context, ProductItem item) {
super(context);
mProductItem = item;
initView(context);
}
/**
* This function sets up all the Views contained in the FrameLayout
*
* #param context
*/
private void initView(Context context) {
addView(LayoutInflater.from(context).inflate(R.layout.list_item_product, null));
ButterKnife.inject(this);
if (mProductItem != null) {
setProductItem(mProductItem);
}
}
2) set object to the view
public void setProductItem(final ProductItem item) {
/**
* Clear Listener. Important!! Cause by Android Recycle View
* Do whatever you want to reset the recycled view or new view
*/
mPurchase.setOnClickListener(null);
endorsed_by_image.setVisibility(INVISIBLE);
endorsed_by_name.setVisibility(INVISIBLE);
mBtnEndorse.setOnCheckedChangeListener(null);
mProductItem = item;
mProductName.setText(mProductItem.getName());
3) In your adapter
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ProductItem item = mProducts.get(position);
if (convertView == null) {
convertView = new ProductListItemView(getActivity(), item);
} else {
((ProductListItemView) convertView).setProductItem(item);
}
}
Hope I explain it well.
And in getView(), it is better to implement ViewHolder. Visit http://www.javacodegeeks.com/2013/09/android-viewholder-pattern-example.html
There's a system visual effect everytime you click a view in Android. In Lollipop it's the ripple effect. When I created a ListView and associated it to an ordinary ArrayAdapter, this effect was present. Now that I've added a custom ListView, this effect is lost.
Now, I've tried to isolate what the problem is, and since using the same list item layout with a default adapter worked nicely, I would say that the problem is on my custom adapter.
I've seen many solutions related to this case that just implemented the ripple effect calling some drawables; this is not what I'm trying to do. The ripple effect shows only because I'm running the app on Android 5, now what I want to do is to have the default system highlight effect for my items when they're being clicked.
Here are the (hopefully) related pieces of my custom adapter:
public class CustomCardSetsAdapter extends BaseAdapter {
List<Card> totalList;
ArrayList<Boolean> hiddenItems;
ListView parentLV;
Integer curPosition = -1;
public static int selectedRowIndex;
public CustomCardSetsAdapter(CardSets cardList, ListView parentListView)
{
this.parentLV = parentListView;
assignSetValues(cardList);
totalList = cardList.getBlackrockMountain();
totalList.addAll(cardList.getClassic());
totalList.addAll(cardList.getCurseofNaxxramas());
totalList.addAll(cardList.getGoblinsvsGnomes());
Collections.sort(totalList,
new Comparator<Card>() {
public int compare(Card f1, Card f2) {
return f1.toString().compareTo(f2.toString());
}
});
hiddenItems = new ArrayList<>();
for (int i = 0; i < totalList.size(); i++) {
if(!totalList.get(i).getCollectible())
hiddenItems.add(true);
else
hiddenItems.add(false);
}
}
#Override
public int getCount() {
return (totalList.size() - getHiddenCount());
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
final int index = getRealPosition(position);
if(convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.card_list_item, parentLV, false);
}
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Integer prevPosition = curPosition;
curPosition = position;
if(prevPosition >= parentLV.getFirstVisiblePosition() &&
prevPosition <= parentLV.getLastVisiblePosition())
{
View view = parentLV.getChildAt(prevPosition- parentLV.getFirstVisiblePosition());
parentLV.getAdapter().getView(prevPosition,view, parentLV);
}
v.setBackgroundColor(Color.WHITE);
}
});
Card curCard = totalList.get(index);
TextView cardName = (TextView) convertView.findViewById(R.id.cardName);
cardName.setText(curCard.getName());
setRarityColor(curCard,cardName);
TextView manaCost = (TextView) convertView.findViewById(R.id.manaCost);
manaCost.setText((curCard.getCost()).toString());
ImageView setIcon = (ImageView) convertView.findViewById(R.id.setIcon);
setSetIcon(curCard,setIcon);
if(position == curPosition)
convertView.setBackgroundColor(Color.WHITE);
else
convertView.setBackgroundColor(Color.TRANSPARENT);
return convertView;
}
#Override
public int getItemViewType(int position) {
return R.layout.card_list_item;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public boolean isEmpty() {
return false;
}
private int getHiddenCount()
{
int count = 0;
for(int i = 0;i <totalList.size();i++)
if(hiddenItems.get(i))
count++;
return count;
}
private int getRealPosition(int position) {
int hElements = getHiddenCountUpTo(position);
int diff = 0;
for(int i=0;i<hElements;i++) {
diff++;
if(hiddenItems.get(position+diff))
i--;
}
return (position + diff);
}
private int getHiddenCountUpTo(int location) {
int count = 0;
for(int i=0;i<=location;i++) {
if(hiddenItems.get(i))
count++;
}
return count;
}
}
Thanks in advance.
in your ListView XML, add:
android:drawSelectorOnTop="true"
I also think you are using your adapter wrong...
Use the ViewHolder Pattern on your Adapter:
public class CustomCardSetsAdapter extends BaseAdapter {
List<Card> totalList;
ArrayList<Boolean> hiddenItems;
ListView parentLV;
Integer curPosition = -1;
public static int selectedRowIndex;
private class ViewHolderRow{
TextView cardName;
TextView manaCost;
ImageView setIcon;
}
public CustomCardSetsAdapter(CardSets cardList, ListView parentListView)
{
this.parentLV = parentListView;
assignSetValues(cardList);
totalList = cardList.getBlackrockMountain();
totalList.addAll(cardList.getClassic());
totalList.addAll(cardList.getCurseofNaxxramas());
totalList.addAll(cardList.getGoblinsvsGnomes());
Collections.sort(totalList,
new Comparator<Card>() {
public int compare(Card f1, Card f2) {
return f1.toString().compareTo(f2.toString());
}
});
hiddenItems = new ArrayList<>();
for (int i = 0; i < totalList.size(); i++) {
if(!totalList.get(i).getCollectible())
hiddenItems.add(true);
else
hiddenItems.add(false);
}
}
#Override
public int getCount() {
return (totalList.size() - getHiddenCount());
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
final int index = getRealPosition(position);
ViewHolderRow theRow;
if(convertView == null) {
theRow = new ViewHolderRow();
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.card_list_item, parentLV, false);
// Cache your views
theRow.cardName = (TextView) convertView.findViewById(R.id.cardName);
theRow.manaCost = (TextView) convertView.findViewById(R.id.manaCost);
theRow.setIcon = (ImageView) convertView.findViewById(R.id.setIcon);
// Set the Tag to the ViewHolderRow
convertView.setTag(theRow);
}else{
// get the Row to re-use
theRow = (ViewHolderRow) convertView.getTag();
}
//... Removed convertView.setOnClickListener
Card curCard = totalList.get(index);
// Set Items
theRow.cardName.setText(curCard.getName());
setRarityColor(curCard,theRow.cardName);
theRow.manaCost.setText((curCard.getCost()).toString());
setSetIcon(curCard,theRow.setIcon);
if(position == curPosition){
convertView.setBackgroundColor(Color.WHITE);
}else{
convertView.setBackgroundColor(Color.TRANSPARENT);
}
return convertView;
}
#Override
public int getItemViewType(int position) {
return R.layout.card_list_item;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public boolean isEmpty() {
return false;
}
private int getHiddenCount()
{
int count = 0;
for(int i = 0;i <totalList.size();i++)
if(hiddenItems.get(i))
count++;
return count;
}
private int getRealPosition(int position) {
int hElements = getHiddenCountUpTo(position);
int diff = 0;
for(int i=0;i<hElements;i++) {
diff++;
if(hiddenItems.get(position+diff))
i--;
}
return (position + diff);
}
private int getHiddenCountUpTo(int location) {
int count = 0;
for(int i=0;i<=location;i++) {
if(hiddenItems.get(i))
count++;
}
return count;
}
}
Set an onListItemClickListener instead of using this on the entire convertView...
yourListView.setOnItemClickListener(ListListener);
private final OnItemClickListener ListListener = new OnItemClickListener{
#Override
public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) {
// ... Do something on click
}
}
Now I have a list view with a custom adapter which shows a different layout types.
List view items are repeating in a random manner and I can't figure out the problem.
So, can anybody help please?
Here is my code.
public class NewsFeedAdapter extends BaseAdapter {
private final int IMAGE_COMPARISON = 0;
private final int POLL = 1;
private final int EMO = 2;
private final int TYPE_MAX_COUNT = EMO + 1;
private ArrayList<Post> posts = new ArrayList<Post>();
private ArrayList<Post> originalPosts = new ArrayList<Post>();
private MaterialDialog alert;
private Context context;
private ApiClient apiClient;
private SharedPreferences sharedPreferences;
private int id;
private Bitmap bitmap;
private ArrayList<View> views ;
private Intent sharingIntent;
private String link;
private String type;
public NewsFeedAdapter(Context context, ArrayList<Post> questionItems) {
this.context = context;
this.posts = questionItems;
this.originalPosts = new ArrayList<Post>(posts);
this.apiClient = ApiClient.getInstance(context);
sharedPreferences = context.getSharedPreferences(context.getResources().getStringArray(R.array.preferences)[4], 0);
views = new ArrayList<>();
}
#Override
public int getCount() {
return posts.size();
}
#Override
public Object getItem(int position) {
return posts.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getViewTypeCount() {
return TYPE_MAX_COUNT;
}
#Override
public int getItemViewType(int position) {
String type = ((Post)getItem(position)).getQ().getType();
if(type.equalsIgnoreCase("radio")){
return POLL;
}else if(type.equalsIgnoreCase("image")){
return IMAGE_COMPARISON;
}else{
return EMO;
}
}
public int getItemViewType(Post post) {
String type = (post).getQ().getType();
if(type.equalsIgnoreCase("radio")){
return POLL;
}else if(type.equalsIgnoreCase("image")){
return IMAGE_COMPARISON;
}else{
return EMO;
}
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
int type = getItemViewType(position);
switch (type) {
case IMAGE_COMPARISON:
ImageListRowView imageListRowView;
// if (convertView == null) {
imageListRowView = new ImageListRowView(context, new MenuListener() {
#Override
public void onReceive(MenuItemAction menuItemAction,int position) {
preformMenuAction(menuItemAction, position);
}
});
imageListRowView.setData(posts.get(position));
imageListRowView.setTag(R.string.view_tag,position);
views.add(imageListRowView);
return imageListRowView;
// }
// else
// imageListRowView = (ImageListRowView) convertView;
//return imageListRowView;
{
case EMO:
EmoListRowView emoListRowView;
// if (convertView == null) {
emoListRowView = new EmoListRowView(context, new MenuListener() {
#Override
public void onReceive(MenuItemAction menuItemAction,int position) {
preformMenuAction(menuItemAction, position);
}
});
emoListRowView.setData(posts.get(position));
emoListRowView.setTag(R.string.view_tag,position);
views.add(emoListRowView);
return emoListRowView;
// }
// else
// emoListRowView = (EmoListRowView) convertView;
// return emoListRowView;
case POLL:
PollListRowView pollListRowView;
// if (convertView == null) {
pollListRowView = new PollListRowView(context, new MenuListener() {
#Override
public void onReceive(MenuItemAction menuItemAction,int position) {
preformMenuAction(menuItemAction, position);
}
});
pollListRowView.setData(posts.get(position));
pollListRowView.setTag(R.string.view_tag,position);
views.add(pollListRowView);
return pollListRowView;
}
// else
// pollListRowView = (PollListRowView) convertView;
// return pollListRowView;
}
return convertView;
}
getView() needs to always customize the rows. The only variance based upon whether convertView is null is whether you have to also inflate the rows.
In each of your case blocks, if convertView is not null, you just return convertView without modification.
give a look at the following question.I think your problem resembles this one.
After scrolling listview, listview items getting repeatedly in android