Simple but little tricky, if I have
list.setAdapter(new ArrayAdapter<String>(this,R.layout.double_row, R.id.doubleRow, articleItemsHelper));
it works if articleItemsHelper is String, but I wanna have HTML formatting in there so when articleItemsHelper is type Spanned this (adapter) doesn't work.
ArrayList<Spanned> articleItemsHelper = new ArrayList<Spanned>();
What's the solution?
EDIT: here is the solution - custom adapter
private static class SpannedAdapter extends BaseAdapter {
private LayoutInflater mInflater;
private ArrayList<Spanned> mArticleList;
public SpannedAdapter(Context context, ArrayList<Spanned> articleList) {
mInflater = LayoutInflater.from(context);
mArticleList = articleList;
}
public int getCount() {
return mArticleList.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.single_row, null);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.singleRow);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(mArticleList.get(position));
return convertView;
}
static class ViewHolder {
TextView text;
}
}
Then just regularly call
list.setAdapter(new SpannedAdapter(this, articleItemsHelper));
where
articleItemsHelper
is
ArrayList<Spanned>
Old thread but I found an other way to do it, it can help people:
simpleAdpt = new ArrayAdapter<Note>(this, R.layout.notelist, listeNotes ){
public View getView(int position, View view, ViewGroup viewGroup)
{
View v = super.getView(position, view, viewGroup);
Note n = (Note) this.getItem(position);
((TextView)v).setText(Html.fromHtml("<b>"+n.getTitre() + "</b> <br/>"+n.getNote()));
return v;
}
};
This is how ArrayAdapter set the text of the rows:
T item = getItem(position);
if (item instanceof CharSequence) {
text.setText((CharSequence)item);
} else {
text.setText(item.toString());
}
As you can see, what it would do in your case is to call the toString method, and that's why it does not work. So, go ahead and write your own adapter, you have no choice in this case.
Related
I'm implementing a ListView with 2 TextViews in it. The first TextView is the name of the product that I'm populating from a query. When I touch any item in the ListView a Dialog appears. When I confirm the Dialog I would like to change the second TextView text to string but whenever I do so every second Textview text changes. For example, if I have 3 items in list view and I click the first one only that item's text view should change instead of all three.
This is my base adapter code:
public class StrengthAdapter extends BaseAdapter {
private ArrayList<Strengths> list;
private LayoutInflater layoutInflater;
private static HashMap<Integer, String> selectedStrengthsMap = new HashMap<Integer, String>();
private String testing;
public StrengthAdapter(Context context, ArrayList<Strengths> list, String test) {
this.list = list;
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.testing = test;
//HashMap<Integer, String> issuesStrengthsbrandNameIDMap = context
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int position) {
return list.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null){
viewHolder = new ViewHolder();
//viewHolder.position = position;
convertView = layoutInflater.inflate(R.layout.strengthslistview, null);
viewHolder.strengthCheckBox = (TextView) convertView.findViewById(R.id.strengthsCheckBox);
viewHolder.chip = convertView.findViewById(R.id.chip);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.strengthCheckBox.setText(((Strengths) list.get(position)).getStrength_title());
viewHolder.chip.setText(testing);
//viewHolder.position = position;
return convertView;
}
public static HashMap<Integer, String> sendSelectedStrengthMap(){
return selectedStrengthsMap;
}
static class ViewHolder {
TextView strengthCheckBox;
TextView chip;
//int position;
}
}
This is how my I set my adapter initially:
strengthListView.setAdapter(new StrengthAdapter(StrengthOfDemandsView.this, strengthsList, "TEST"));
and this is how I set my adapter after closing the dialog:
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
strengthListView.setAdapter(new StrengthAdapter(StrengthOfDemandsView.this, strengthsList, "TEST123"));
}
});
You need to handle clicks inside of your adapter and not setting adapter every time click happens. It have to look like this:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null){
viewHolder = new ViewHolder();
//viewHolder.position = position;
convertView = layoutInflater.inflate(R.layout.strengthslistview, null);
viewHolder.strengthCheckBox = (TextView) convertView.findViewById(R.id.strengthsCheckBox);
viewHolder.chip = convertView.findViewById(R.id.chip);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.strengthCheckBox.setText(((Strengths) list.get(position)).getStrength_title());
convertView.setOnClickListener(
// show dialog here and then in positiveButton callback call
//viewHolder.chip.setText(testing);
);
return convertView;
}
First of all inflate your layout before creation of holder.
Then you need to define onclick behavior by implementing onclicklistener. I updated your getView method please implement this as follows:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null){
convertView = layoutInflater.inflate(R.layout.strengthslistview, null);
viewHolder = new ViewHolder();
//viewHolder.position = position;
viewHolder.strengthCheckBox = (TextView) convertView.findViewById(R.id.strengthsCheckBox);
viewHolder.chip = convertView.findViewById(R.id.chip);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.strengthCheckBox.setText(((Strengths) list.get(position)).getStrength_title());
viewHolder.chip.setText(testing);
//viewHolder.position = position;
convertView.setOnClickListener(
//you can do your job here what u want to do by clicking specific row
);
return convertView;
}
Also write your functionalities in the block I mentioned above in comments.
can you give me some advice about my getView methood;
I have custom adapter that extends ArrayAdapter(context, id, list)
public class myCustomAdapter extends ArrayAdapter{
private List obj = null;
public myCustomAdapter(#NonNull Context context, #LayoutRes int resource, #NonNull List objects) {
super(context, resource, objects);
obj = objects;
}
#Override
public int getCount() {
return obj.size();
}
#Nullable
#Override
public Object getItem(int position) {
return super.getItem(position);
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
Task myTask = (Task) getItem(position);
if(convertView==null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent);
}
TextView myTextView = (TextView) convertView.findViewById(R.id.textView);
myTextView.setText(myTask.getTaskText());
CheckBox myCheckBox = (CheckBox) convertView.findViewById(R.id.checkBox);
myCheckBox.setChecked(myTask.getChecked());
return convertView;
}
}
problem 1 : super: Unchecked call to ArrayAdapter(..) as member of raw type
problem 3 : getTaskText //methood from my Task class// may produce NPE
I would appreciate any help if possible.
if(convertView!=null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent);
}
should be
if(convertView==null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent);
}
you have to inflate when the convertview is null. not when its not null. And then return this from your getView() method
Also i can not see getCount() method. It is also very important to tell the adapter about how many items to inflate
Change this
return super.getView(position, convertView, parent)
to
return convertView;
You have to inflate convertview when it is null.
if(convertView==null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent);
}
Also return convertview instead of super
I suggest use BaseAdapter, it's basic, ArrayAdapter is BaseAdapter' subclass, In most cases, you do not need to inherit the BaseAdapter, use it directly.
ArrayAdapter adapter = new ArrayAdapter(context, R.layout.list_item, R.id.text, stringList);
public class MyCustomAdapter extends BaseAdapter {
private List<Task> listData;
public MyCustomAdapter(List<Task> list) {
listData = list;
}
#Override
public int getCount() {
return listData.size();
}
#Override
public Object getItem(int position) {
return listData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
}
Task data = getItem(position);
TextView text = (TextView) convertView.findViewById(R.id.text);
return convertView;
}
}
Whats wrong with this adapter, when i scroll down i see repeated rows at the bottom and then when scroll up again i see also repeated rows at the top that were not exist before, and the rest of Data items does not appear
the adapter:
public class ClassesListViewAdapter extends BaseAdapter {
private Context mContext;
ArrayList<String> Data = new ArrayList<>();
public ClassesListViewAdapter(Context context, ArrayList<String> data) {
Data = data;
mContext = context;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getCount() {
return Data.size();
}
private class ViewHolder{
TextView ClassDataTV;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = ((Activity)mContext).getLayoutInflater();
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.classes_list_view_item, parent, false);
holder = new ViewHolder();
holder.ClassDataTV = (TextView) convertView.findViewById(R.id.ClassDataTV);
holder.ClassDataTV.setText(Data.get(position));
convertView.setTag(holder);
}else{
holder=(ViewHolder)convertView.getTag();
}
return convertView;
}
}
and here how i use it:
ArrayList<String> v = new ArrayList<>();
v.add("AAAAAAA");
v.add("WWWWWwW");
v.add("VVVVVVV");
v.add("SSSSSSSSS");
v.add("QQQQQQQQQ");
v.add("YYYYYYYY");
v.add("TTTTTTT");
v.add("UUUUUUUUUU");
v.add("zzzzzzzzzzzz");
v.add("CCCCCCCCCC");
v.add("HHHHHHHHHHH");
v.add("IIIIIIIIII");
v.add("PPPPPPPPP");
mListView.setAdapter(new ClassesListViewAdapter(getActivity(), v));
Put following part of your code outside if-block and it will be fixed :
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = ((Activity)mContext).getLayoutInflater();
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.classes_list_view_item, parent, false);
holder = new ViewHolder();
holder.ClassDataTV = (TextView) convertView.findViewById(R.id.ClassDataTV);
convertView.setTag(holder);
}else{
holder=(ViewHolder)convertView.getTag();
}
// initialize your view here
holder.ClassDataTV.setText(Data.get(position));
return convertView;
}
The logic behind ViewHolder pattern tells that you should do it in this way. when you scroll some of reference will not created again and else block called so this cause your list not updated as you expected.
I am making a messaging android app, but my question is, how can I make the app choose either to pick the right hand layout or left hand layout? Like we see in messaging apps like WhatsApp, if I am the sender, my Message is wrapped in a right hand layout whilst the persons messages am chatting with are wrapped in a left handed layout, How can I achieve this type of Interface or layout I should say?
Below is my code, the app simple receives data from a remote database and puts it in a listview, using a custom adapter:
// the Data being set to the adapter
private ArrayList<ListItem> getListData() {
ArrayList<ListItem> listMockData = new ArrayList<ListItem>();
String[] username = mUsername.toArray(new String[mUsername.size()]);
String[] comments = Comment.toArray(new String[Comment.size()]);
for (int i = 0; i < username.length; i++) {
ListItem newsData = new ListItem();
newsData.setUsername(username[i]);
newsData.setmComment(comments[i]);
listMockData.add(newsData);
System.gc();
}
return listMockData;
}
And my custom adapter utilizing a single view:
public class CommentAdapter extends BaseAdapter{
private ArrayList<ListItem> listData;
private LayoutInflater layoutInflater;
ViewHolder holder;
public CommentAdapter(Context context, ArrayList<ListItem> listData) {
this.listData = listData;
notifyDataSetChanged();
layoutInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return listData.size();
}
#Override
public Object getItem(int position) {
return listData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.singlecomment, null);
holder = new ViewHolder();
holder.username = (TextView) convertView.findViewById(R.id.usernme);
holder.message = (TextView) convertView.findViewById(R.id.postCommentBox);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
ListItem newsItem = listData.get(position);
holder.username.setText(newsItem.getUsername());
holder.message.setText(newsItem.getmComment());
return convertView;
}
static class ViewHolder {
TextView username;
TextView message;
}
}
Assuming that your ListItem object has a field named isSender to check whether he is the sender or not.
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.singlecomment, null);
holder = new ViewHolder();
holder.username = (TextView) convertView.findViewById(R.id.usernme);
holder.message = (TextView) convertView.findViewById(R.id.postCommentBox);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
ListItem newsItem = listData.get(position);
if(newsItem.getIsSender()) {
holder.usernameRight.setText(newsItem.getUsername());
holder.messageRight.setText(newsItem.getmComment());
holder.usernameLeft.setVisibility(View.GONE); // or something like that to hide
holder.messageLeft.setText(View.GONE);
} else {
holder.usernameLeft.setText(newsItem.getUsername());
holder.messageLeft.setText(newsItem.getmComment());
holder.usernameRight.setVisibility(View.GONE);
holder.messageRight.setText(View.GONE);
}
return convertView;
}
I have a conversation mode in my application where I wish to load one layout for one user and another layout for the other. It need not always be alternating hence I cannot use a simple "%2" to achieve it.
Based on a flag I am assigning a dynamic layout, which works. My problem is that as I scroll the layouts get distorted as in, conversation of user_1 will get layout_2 or conversation of user_2 will get layout_1, absolutely random.
I did something similar to an answer I saw here:
https://stackoverflow.com/a/16774696/4810718
There were a few posts about randomized data. That is not my issue, the order of the list items does not change however the layout get's randomly applied. I read that the items in view + 1 are kept in temporary memory, regarding this another thing I noticed was: as I keep adding items such that the scrollbar comes into picture when I add a second item outside the visibility it tends to get the layout of the topmost item (first item) visible. Scrolling would later give me seemingly randomized results.
public class ConversationAdapter extends BaseAdapter
{
private LayoutInflater inflater;
private ArrayList<ConversationContent> objects;
ImageView user;
static int ind = 0;
private class ViewHolder
{
TextView textView1;
TextView textView2;
TextView textView3;
}
public ConversationAdapter(Context context, ArrayList<ConversationContent> objects)
{
inflater = LayoutInflater.from(context);
this.objects = objects;
}
public int getCount()
{
return objects.size();
}
public ConversationContent getItem(int position)
{
return objects.get(position);
}
public long getItemId(int position)
{
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder = null;
if(convertView == null)
{
holder = new ViewHolder();
if (Main_Page3.convFlag == 1)
{
convertView = inflater.inflate(R.layout.conversation_item_1, null);
}
else
{
convertView = inflater.inflate(R.layout.conversation_item_2, null);
}
holder.textView1 = (TextView) convertView.findViewById(R.id.trans);
holder.textView1.setTypeface(Main_Activity.fontC);
holder.textView2 = (TextView) convertView.findViewById(R.id.lang);
holder.textView2.setTypeface(Main_Activity.fontC);
holder.textView3 = (TextView) convertView.findViewById(R.id.user);
holder.textView3.setTypeface(Main_Activity.fontC);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
holder.textView1.setText(objects.get(position).getTranslatedText());
holder.textView2.setText(objects.get(position).getTranslationString());
SpannableString originalTextString = new SpannableString("\n" + objects.get(position).getOriginalText());
originalTextString.setSpan(new RelativeSizeSpan(0.5f), 0, originalTextString.length(), 0);
holder.textView1.append(originalTextString);
holder.textView3.setText(objects.get(position).getUser());
return convertView;
}
}
So, that's the code I've written. A possible solution I thought of was if I used an array of views and loaded them accordingly, it may work? I'm really not really sure how I should be going about doing this - I'm still pretty new to Android.
I've searched a bit but could not get a helpful solution. Please direct me to a helpful solution you find or, a working answer would be most appreciable. Thank you.
I think the best way to achieve what you want is to put the flag to determine which layout to use on your ConversationContent object, then override getViewTypeCount() and getItemViewType(int position) something like this:
#Override
int getViewTypeCount() {
return 2;
}
#Override
int getItemViewType(int position) {
if (objects.get(position).isReply()) { //isReply can be whatever you want to determine whether to change layout
return 1;
}
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder = null;
if(convertView == null)
{
holder = new ViewHolder();
if (getItemViewType(position) == 1)
{
convertView = inflater.inflate(R.layout.conversation_item_1, null);
}
else
{
convertView = inflater.inflate(R.layout.conversation_item_2, null);
}
holder.textView1 = (TextView) convertView.findViewById(R.id.trans);
holder.textView1.setTypeface(Main_Activity.fontC);
holder.textView2 = (TextView) convertView.findViewById(R.id.lang);
holder.textView2.setTypeface(Main_Activity.fontC);
holder.textView3 = (TextView) convertView.findViewById(R.id.user);
holder.textView3.setTypeface(Main_Activity.fontC);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
holder.textView1.setText(objects.get(position).getTranslatedText());
holder.textView2.setText(objects.get(position).getTranslationString());
SpannableString originalTextString = new SpannableString("\n" + objects.get(position).getOriginalText());
originalTextString.setSpan(new RelativeSizeSpan(0.5f), 0, originalTextString.length(), 0);
holder.textView1.append(originalTextString);
holder.textView3.setText(objects.get(position).getUser());
return convertView;
}
For listview adapter, if you want to show different layout,
like conversion mode. you would better override the following two methods:
//set your layout type here
public int getItemViewType(int position)
{
return 0;
}
//the layout count in your adapter
public int getViewTypeCount()
{
return 0;
}
Here is an example you can refer to:
public class ChatMessageAdapter extends BaseAdapter
{
private LayoutInflater mInflater;
private List<ChatMessage> mDatas;
public ChatMessageAdapter(Context context, List<ChatMessage> mDatas)
{
mInflater = LayoutInflater.from(context);
this.mDatas = mDatas;
}
#Override
public int getCount()
{
return mDatas.size();
}
#Override
public Object getItem(int position)
{
return mDatas.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public int getItemViewType(int position)
{
ChatMessage chatMessage = mDatas.get(position);
if (chatMessage.getType() == Type.INCOMING)
{
return 0;
}
return 1;
}
#Override
public int getViewTypeCount()
{
return 2;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
ChatMessage chatMessage = mDatas.get(position);
ViewHolder viewHolder = null;
if (convertView == null)
{
if (getItemViewType(position) == 0)
{
convertView = mInflater.inflate(R.layout.item_from_msg, parent,
false);
viewHolder = new ViewHolder();
viewHolder.mDate = (TextView) convertView
.findViewById(R.id.id_form_msg_date);
viewHolder.mMsg = (TextView) convertView
.findViewById(R.id.id_from_msg_info);
} else
{
convertView = mInflater.inflate(R.layout.item_to_msg, parent,
false);
viewHolder = new ViewHolder();
viewHolder.mDate = (TextView) convertView
.findViewById(R.id.id_to_msg_date);
viewHolder.mMsg = (TextView) convertView
.findViewById(R.id.id_to_msg_info);
}
convertView.setTag(viewHolder);
} else
{
viewHolder = (ViewHolder) convertView.getTag();
}
//set data here
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
viewHolder.mDate.setText(df.format(chatMessage.getDate()));
viewHolder.mMsg.setText(chatMessage.getMsg());
return convertView;
}
private final class ViewHolder
{
TextView mDate;
TextView mMsg;
}
}