I'm developing an android application which has background photos
so I decided to make my listView or recyclerView transparent to show these backgrounds
every thing works good except on lollipop version!
I want to make the lollipop version like all previous versions like kitkat
here is the code snippet that I use to set the transparency of each item
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder mHolder;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.dairy_item, parent, false);
CardView listItem = (CardView) convertView.findViewById(R.id.dairy_card);
listItem.setCardElevation(5);
listItem.setUseCompatPadding(true);
// listItem.setPadding(0, 0, 5, 6);
listItem.setPreventCornerOverlap(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
Drawable mBackground = listItem.getBackground();
mBackground.setAlpha(127);
listItem.setBackground(mBackground);
} else {
listItem.getBackground().setAlpha(127);
}
mHolder = new ViewHolder();
mHolder.typeIcon = (ImageView) convertView.findViewById(R.id.reminder_icon);
mHolder.title = (TextView) convertView.findViewById(R.id.reminder_identifier);
mHolder.subtitle = (TextView) convertView.findViewById(R.id.reminder_status);
mHolder.time = (TextView) convertView.findViewById(R.id.item_time);
mHolder.order = (TextView) convertView.findViewById(R.id.item_order);
convertView.setTag(mHolder);
} else
mHolder = (ViewHolder) convertView.getTag();
mHolder.typeIcon.setImageResource(imgRec[position]);
mHolder.title.setText(title[position]);
mHolder.subtitle.setText(subtitle[position]);
String orders = String.valueOf(position + 1);
if (SettingsFragment.isArabic(mContext))
orders = Referances.ArabtizeDigits(mContext, orders);
mHolder.order.setText(orders);
mHolder.time.setText(time[position]);
return convertView;
}
from my own listView adapter.
thanks in advance ....
Related
I am just adapting my custom adapter code with ViewHolder so that i can optimize my list view with a recycler, but i am not sure if i do it right.
My view holder class:
public class ViewHolderTask {
int positionHolder;
TextView nameHolder;
TextView timeHolder;
TextView sessionHolder;
TextView dateHolder;
FloatingActionButton mFabTaskHolder;
public ViewHolderTask(View v, int position) {
this.positionHolder = position;
this.nameHolder = v.findViewById(R.id.taskNameText);
this.timeHolder = v.findViewById(R.id.timeTextView);
this.sessionHolder = v.findViewById(R.id.textViewSession);
this.dateHolder = v.findViewById(R.id.dateTextView);
this.mFabTaskHolder = v.findViewById(R.id.myFabTask);
}
My custom adapter class:
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
ViewHolderTask holder;
if(convertView == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE );
convertView = inflater.inflate(R.layout.task_row, parent, false);
holder = new ViewHolderTask(convertView, position);
convertView.setTag(holder);
}else{
holder = (ViewHolderTask) convertView.getTag();
}
Task task = taskArrayList.get(position);
//set the configurations
holder.getTimeHolder().setText(getTimeString(task.getTime()));
holder.getNameHolder().setText(task.getName());
holder.getDateHolder().setText(getDateString(task.getDate()));
holder.getSessionHolder().setText(getSessionString(task.getSession()));
//Set the FAB listener
addFabListener(holder.getmFabTaskHolder(), position);
//set the clicked background
if(TaskActivity.getIsClicked() && TaskActivity.getPositionClicked()-1 == position){
convertView.setBackgroundResource(R.color.backgroundSelectedItem);
}
return convertView;
}
Do I use it right?
Seems to be fine for me other than this portion of the code
//set the clicked background
if(TaskActivity.getIsClicked() && TaskActivity.getPositionClicked()-1 == position){
convertView.setBackgroundResource(R.color.backgroundSelectedItem);
}
You might need to reset the background resource back to default for the item which is not clicked. maybe you have to add "else" part to the "if"
I have a custom adapter class for a listview and I want to be able to access the content of a specific row by clicking a button on it. I tried to create a ViewHolder, but I get a NPE error when I try to click it.
static class ViewHolder {
TextView camera;
TextView players;
TextView max_players;
ImageView privata;
Button Buton;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
String variabile[] = getItem(position).split("\\s+");
LayoutInflater linflater = LayoutInflater.from(getContext());
View customView = linflater.inflate(R.layout.custom_row, parent, false);
final ViewHolder holder = new ViewHolder();
holder.camera = (TextView) customView.findViewById(R.id.Nume);
holder.players = (TextView) customView.findViewById(R.id.players);
holder.max_players = (TextView) customView.findViewById(R.id.max_players);
holder.privata = (ImageView) customView.findViewById(R.id.privata);
holder.Buton = (Button) customView.findViewById(R.id.Buton);
holder.camera.setText(variabile[0]);
if (!variabile[1].equals("true")) {
parola = false;
holder.privata.setVisibility(View.INVISIBLE);
}
holder.players.setText(variabile[2]);
holder.max_players.setText(variabile[3]);
room_id = variabile[4];
nume = variabile[5];
holder.Buton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
hash = new HashMap<String, String>();
hash.put("name", nume);
hash.put("room", room_id);
if (intra) {
holder.Buton.setText("Iesi");
site = siteul + "/join";
intra = false;
} else {
holder.Buton.setText("Intra");
site = siteul + "/leave";
intra = true;
}
new ATask().execute(site);
}
});
return customView;
}
When using the ViewHolder pattern, you should check if the convertView in null or has been created before, in the getView method, and after that use setTag and getTag methods. like this :
if (convertView == null)
{
LayoutInflater linflater = LayoutInflater.from(getContext());
convertView = linflater.inflate(R.layout.your_list_item_view, parent, false);
viewHolder.textView = (TextView)convertView.findViewById([the id]);
.
.
.
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
You need to check if the convertView is null so it is already has been visited or not then store the holder in tag Like
ViewHolder holder;
if (convertView == null) {
LayoutInflater linflater = LayoutInflater.from(getContext());
holder = linflater.inflate(R.layout.custom_row, parent, false);....
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}//Common code
I have an android app where i want to display some messages.The messages are classified into two categories, images and text.Text messages have two types,sent and received.I have created a custom listview adapter to display the messages in a listview.When calling the adapter,i pass an arraylist of 13 objects.Problem is not all the messages in arraylist are displayed.Only the first five messages are displayed.The messages are displayed three times each.When a message item in the listview is clicked,more than one message is highlited.What could be the problem.
Here is the listview adapter:
public class CustomMessageListAdapter extends BaseAdapter {
private ArrayList<?> listData;
private LayoutInflater layoutInflater;
public CustomMessageListAdapter(Context context, ArrayList<?> listData) {
this.listData = listData;
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;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.listview_message,
null);
viewHolder = new ViewHolder();
viewHolder.incoming_message = (RelativeLayout) convertView
.findViewById(R.id.received_layout);
viewHolder.outgoing_message = (RelativeLayout) convertView
.findViewById(R.id.sent_layout);
viewHolder.sent_message = (TextView) convertView
.findViewById(R.id.sent_messages_textView_message);
viewHolder.sent_time = (TextView) convertView
.findViewById(R.id.sent_messages_textview_time);
viewHolder.sent_image = (ImageView) convertView
.findViewById(R.id.sent_image_imageview);
viewHolder.received_image = (ImageView) convertView
.findViewById(R.id.received_image_imageview);
viewHolder.sent_image_layout = (RelativeLayout) convertView
.findViewById(R.id.sent_image_layout);
viewHolder.received_image_layout = (RelativeLayout) convertView
.findViewById(R.id.received_image_layout);
viewHolder.received_message = (TextView) convertView
.findViewById(R.id.messages_textView_message);
viewHolder.received_time = (TextView) convertView
.findViewById(R.id.messages_textview_time);
viewHolder.date = (TextView) convertView
.findViewById(R.id.messages_textView_date);
viewHolder.sent_hepasnap = (RelativeLayout) convertView
.findViewById(R.id.chat_layout_sent_hepasnap);
viewHolder.recieved_hepasnap = (RelativeLayout) convertView
.findViewById(R.id.chat_layout_received_hepasnap);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
MessageItem messageItem = (MessageItem) listData.get(position);
Log.i("msg", "" + position);
if (messageItem.getCategory().equalsIgnoreCase("text")) {
if (messageItem.getType().equalsIgnoreCase("sent")) {
viewHolder.outgoing_message.setVisibility(View.VISIBLE);
viewHolder.sent_message.setText(messageItem.getMessage());
viewHolder.sent_time.setText(messageItem.getTime());
} else {
viewHolder.incoming_message.setVisibility(View.VISIBLE);
viewHolder.received_message.setText(messageItem.getMessage());
viewHolder.received_time.setText(messageItem.getTime());
}
}
return convertView;
}
public class ViewHolder {
TextView sent_message;
TextView sent_time;
TextView received_message;
TextView received_time;
RelativeLayout outgoing_message;
RelativeLayout incoming_message;
RelativeLayout sent_hepasnap;
RelativeLayout recieved_hepasnap;
TextView date;
ImageView sent_image;
ImageView received_image;
RelativeLayout sent_image_layout;
RelativeLayout received_image_layout;
}
}
And when message is clicked:
add viewHolder.incoming_message.setVisibility(View.GONE); to if condition
(messageItem.getType().equalsIgnoreCase("sent"))
and viewHolder.outgoing_message.setVisibility(View.GONE); to else condition.
If your Problem not solved then let me know.
I think the messages are getting displayed multiple times because they carry older values whenever convert view is non-null.
And since your incoming and outgoing messages are both getting filled it is giving the illusion of multiple items getting selected.
So you should change visibility of unused views to View.GONE.
My initial question was posted here:
ListView for messaging app shows wrong listItem layout after scrolling
But I am a bit confused since there are two answers that were upvoted and I'd like to use both of them. First, I think it is a safe assumption that I should use the getItemViewType method to help me with performance. After that though, should I still use the viewHolder pattern as described in Googles documentation on Making ListView Scrolling Smooth?
If I do use the ViewHolder code, do I incorporate it into getView?
static class ViewHolder {
TextView text;
TextView timestamp;
ImageView icon;
ProgressBar progress;
int position;
}
static public enum LAYOUT_TYPE {
INBOUND,
OUTBOUND
}
#Override
public int getViewTypeCount () {
return LAYOUT_TYPE.values().length;
}
#Override
public int getItemViewType (int position) {
if ( messages.get(position).isOutbound())
return LAYOUT_TYPE.OUTBOUND.ordinal();
else
return LAYOUT_TYPE.INBOUND.ordinal();
}
#Override
public View getView (int position, View convertView, ViewGroup parent) {
LAYOUT_TYPE itemType = LAYOUT_TYPE.values()[getItemViewType(position)];
... (code until inflater )
switch (itemType){
case INBOUND:
convertview = /inflate & configure inbound layout
ViewHolder holder = new ViewHolder();
holder.icon = (ImageView) convertView.findViewById(R.id.listitem_image);
holder.text = (TextView) convertView.findViewById(R.id.listitem_text);
holder.timestamp = (TextView) convertView.findViewById(R.id.listitem_timestamp);
holder.progress = (ProgressBar) convertView.findViewById(R.id.progress_spinner);
convertView.setTag(holder);
break;
case OUTBOUND:
convertview = /inflate & configure outbound layout
ViewHolder holder = new ViewHolder();
holder.icon = (ImageView) convertView.findViewById(R.id.listitem_image);
holder.text = (TextView) convertView.findViewById(R.id.listitem_text);
holder.timestamp = (TextView) convertView.findViewById(R.id.listitem_timestamp);
holder.progress = (ProgressBar) convertView.findViewById(R.id.progress_spinner);
convertView.setTag(holder);
break;
}
//Typical getView
public View getView(int position, View containerRow, ViewGroup parent) {
if (containerRow == null) {
//One time inflate
containerRow = inflater.inflate(R.layout.yourLayout, parent, false);
//instantiate all view from layout in levent relevent object.
//One time instantiation of viewholder
viewHolder = new ViewHolder();
viewHolder.someview = viewFromLayou;
//finally
containerRow.setTag(viewHolder);
}
else{
viewHolder = (ViewHolder) containerRow.getTag();
}
}
//In your case it should be
public View getView(int position, View containerRow, ViewGroup parent) {
if (containerRow == null) {
//One time inflate
containerRow = inflater.inflate(R.layout.yourLayout, parent, false);
//instantiate all view from layout in levent relevent object.
//One time instantiation of viewholder
if(inbound)
inBoundViewHolder = new ViewHolder();
else
outBoundViewHolder = new ViewHolder();
viewHolder.someview = viewFromLayou;
//finally
containerRow.setTag(viewHolder);
}
else{
viewHolder = (ViewHolder) containerRow.getTag();
}
}
I created my own adapter that extend BaseAdapter and I use it for GridView. I want to get the number of element and put it into TextView. I did it in my adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if(convertView == null){
gridView = new View(context);
gridView = inflater.inflate(R.layout.grid_element, null);
ImageView logo = (ImageView) gridView.findViewById(R.id.grid_logo);
TextView tv = (TextView) gridView.findViewById(R.id.grid_textView1);
tv.setText(level+position);
}
else
gridView = convertView;
return gridView;
}
It seems to be good until I get elements that are not in the screen in launch:
The position is like reseted.
How can I do it properly?
You were not setting the TextView properly when convertView was not null. Try this:
if (convertView == null) {
gridView = inflater.inflate(R.layout.grid_element, null);
} else {
gridView = convertView;
}
ImageView logo = (ImageView) gridView.findViewById(R.id.grid_logo);
TextView tv = (TextView) gridView.findViewById(R.id.grid_textView1);
tv.setText(level + position);
May help new Visitors.
You have to know two main things :
You need to check if convertView is null, in order to know if that row in your list is not created yet (convertView = null) or is being recycled by the adapter (convertView != null). This is called the Recycling process.
Another important thing to know is the View Holder Pattern. Calling findViewById() on each row of getView() method is to heavy for list populating and slows down scrolling performance. To avoid that, create a static class with some views as class fields. Than use findViewById() if the view is being created (convertView == null), and get it back from getTag() method when it's being recycled
`
static class ViewHolder {
TextView text;
ImageView icon;
}
ViewHolder holder;
if(convertView == null) {
convertView = inflater.inflate(resource, root);
holder = new ViewHolder();
holder.icon = (ImageView) convertView.findViewById(R.id.listitem_image);
holder.text = (TextView) convertView.findViewById(R.id.listitem_text);
holder.timestamp = (TextView) convertView.findViewById(R.id.listitem_timestamp);
holder.progress = (ProgressBar) convertView.findViewById(R.id.progress_spinner);
convertView.setTag(holder);
}
holder = (ViewHolder) convertView.getTag();
// Set here your view's content :
holder.text.setText("Sample");
// ...