Reputation: 1741
I have a problem with creating a GridView-based calendar. Here is the Grid:
This is supposed to be a calendar populated with events, so I have my adapter implement OnClickListener and I set that listener for every button in the calendar. It works perfectly for every single button EXCEPT the first one(in this case number 30). When I click it just doesn't work, but when I click on another button after I have attempted to click on the first one, it performs the click for the first one just before performing the click for the other button.
I've scanned about 10 pages of relevant questions and have not found someone to have this problem. Help please!
As asked, here is the getView function of my code:
public View getView(int position, View convertView, ViewGroup parent)
{
View row = convertView;
ViewHolder holder;
if (row == null)
{
holder = new ViewHolder();
LayoutInflater inflater = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.calendar_day_gridcell, parent, false);
holder.gridCell = (Button) row.findViewById(R.id.calendar_day_gridcell);
holder.multiDayEvent = (EventLengthView)row.findViewById(R.id.eventLengthView);
}
else{
holder = (ViewHolder)row.getTag();
}
int calendarGridHeight = (calendarView.getHeight()-5)/(getCount()/7);
AbsListView.LayoutParams params = new AbsListView.LayoutParams(
android.view.ViewGroup.LayoutParams.FILL_PARENT,
calendarGridHeight);
row.setLayoutParams(params);
//Change the background drawable depending on the position in the calendar
if ((position+1) % 7 == 0){
holder.gridCell.setBackgroundDrawable(getResources().getDrawable(R.drawable.calendar_button_selector_end_row));
}
if (getCount() - position < 8){
holder.gridCell.setBackgroundDrawable(getResources().getDrawable(R.drawable.calendar_button_selector_end_column));
}
if (position == getCount()-1){
holder.gridCell.setBackgroundDrawable(getResources().getDrawable(R.drawable.calendar_button_selector_end));
}
holder.gridCell.setOnClickListener(this);
holder.gridCell.setTag(null);//clear tags
// ACCOUNT FOR SPACING
String[] day_color = list.get(position).split("-");
int theday = Integer.parseInt(day_color[0]);
int themonth = Integer.parseInt(day_color[2]);
int theyear = Integer.parseInt(day_color[3]);
String date = DateFormat.format("dd/M/yy", new Date(theyear,themonth,theday)).toString();
if ((!eventsMap.isEmpty()) && (eventsMap != null))
{
if (eventsMap.containsKey(date))
{
holder.multiDayEvent.SetMeasure(calendarView.getWidth()/7, calendarGridHeight);
holder.multiDayEvent.setVisibility(View.VISIBLE);
//holder.singleDayEvent.setVisibility(View.VISIBLE);
Event event = (Event) eventsMap.get(date);
holder.multiDayEvent.AddEvent(event);
holder.gridCell.setTag(event);
}
else{
//holder.singleDayEvent.setVisibility(View.GONE);
holder.multiDayEvent.setVisibility(View.GONE);
}
}
// Set the Day GridCell
holder.gridCell.setText(Integer.toString(theday));
if (day_color[1].equals("GREY"))
{
holder.gridCell.setTextColor(Color.GRAY);
}
if (day_color[1].equals("WHITE"))
{
holder.gridCell.setTextColor(Color.WHITE);
}
if (day_color[1].equals("BLUE"))
{
holder.gridCell.setTextColor(Color.BLUE);
}
row.setTag(holder);
return row;
}
public class ViewHolder{
Button gridCell;
ImageView singleDayEvent;
EventLengthView multiDayEvent;
}
public void onClick(View view)
{
if (view.getTag() != null){
Event event = (Event)view.getTag();
eventListView.setAdapter(new EventListAdapter(CalendarScreen.this, event));
eventListViewLayout.setVisibility(View.VISIBLE);
eventListViewLayout.startAnimation(fadeIn);
}
else if (eventListViewLayout.getVisibility() == View.VISIBLE){
onBackPressed();
}
}
The onClick gets called for every gridcell EXCEPT the first one in the top left corner
Upvotes: 22
Views: 14489
Reputation: 107
After spending so many days, set layout params as follows..
if (view == null) {
// call the user's implementation
view = mInflater.inflate(mViewId, null);
holder = createHolder(view);
// we set the holder as tag
view.setTag(holder);
rlMainCell = (RelativeLayout)view.findViewById(R.id.rlMainCell);
rlMainCell.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) view.getResources().getDimension(R.dimen._128sdp)));
} else {
// get holder back...much faster than inflate
holder = (ViewHolder) view.getTag();
}
it works absolutely fine to me
Upvotes: 0
Reputation: 146
Ok, I found the solution. The problem was these lines:
ViewHolder holder;
if (convertView == null)
{
holder = new ViewHolder();
LayoutInflater inflater = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.calendar_day_gridcell, parent, false);
holder.gridCell = (Button) convertView.findViewById(R.id.calendar_day_gridcell_button);
holder.multiDayEvent = (EventLengthView) convertView.findViewById(R.id.eventLengthView);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
When putting instatiating the gridCell button there, somehow, it mixes up the click listener of the first position in the adapter. I ended up fixing it by just instatiating the holder in every pass, instead of getting it by tag (which is better for performance, but oh well). Thanks everyone for the help.
Upvotes: 8
Reputation: 521
I had the same problem.Keeping the setLayoutParams inside the if(view == null) clause worked out. You dont have to sacrifice view recyling in that way.
like :
if(row == null){
// inflate row
row.setLayoutParams(params);
//remaining code
}else{
holder = (ViewHolder)row.getTag();
}
// everything else
I don't know why it works but it worked for me. I also noticed that all codes regarding the same issue in stackoverflow had also used setLayoutParams outside the if clause. This is my first time so i dont know if i can post this everywhere. Hope it helped .
Source : Lot of trail and error .
Upvotes: 15
Reputation: 71
I had this same issue. The click event on the first item was significantly delayed. I was already using notifyDataSetInvalidated(). Using onItemClickListener() solved the issue, although I still don't understand why the onClick listener on the individual items has this behavior.
Upvotes: 1
Reputation: 1554
Use your OnClickListener() in your activity after .setAdapter() method, not in your adapter class.
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position, long id) {
Toast.makeText(GridViewActivity.this, "" + position,
Toast.LENGTH_SHORT).show();
}
});
Upvotes: 9
Reputation: 91
For what it's worth, I had also this issue (first cell in the gridview having delayed onclick).
In my case, I was using a (lightly customized) gridviews with dynamic sets of imageviews that I would make visible/gone and redraw the gridview. All imageviews where prepared beforehand and stored in the adapter.
Initially, I used notifyDataSetChanged() on the adapter but this resulted in the delayed click problem for the first cell whenever the set was updated. I changed to just invalidating the gridview and now things are fine. Bear in mind that all my views are already created and stored in the adapter, its just the getview method that checks which ones are really visible.
Upvotes: 1
Reputation: 1325
Set onItemClickListener on the GridView object instead of setting onClickListeners on each button.
And I found another question with your problem here. Bounty maybe?
Upvotes: 0