RecyclerView, GridLayoutManager and dynamic Spans count

泄露秘密 提交于 2020-01-23 12:18:49

问题


I encountered a strange bug with the recyclerview. I set and resize spans dynamically to fit with the informations downloaded from an AsyncTask.

Sometimes it doesn't display properly. It seems like it displays over the screen.!

Then after one or more reload it displays correctly. It seems to go out the screen but I can't figure out why.

Here is my adapter:

   public class ScheduleAdapter extends RecyclerView.Adapter<ScheduleAdapter.ViewHolder> {

    private List<Schedule> mDataset;
    /**
     * First parameter is the position in the dataset
     * The value returned is the number of schedules to display
     */
    private TreeMap<Integer, Integer> schedulesToDisplay;
    private int maxSpans;

    private static final String TAG="LINE_ADATER";

    // Provide a suitable constructor (depends on the kind of dataset)
    public ScheduleAdapter() {
        mDataset = new ArrayList<Schedule>();
        schedulesToDisplay = new TreeMap<Integer, Integer>();
    }

    // Create new views (invoked by the layout manager)
    @Override
    public ScheduleAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // create a new view
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_schedule, parent, false);
        // set the view's size, margins, paddings and layout parameters
        ViewHolder vh = new ViewHolder((LinearLayout) v);
        return vh;
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element
        Log.d(""+position, "BINDVIEW");
        holder.setItem(mDataset.get(position));
        Schedule s = mDataset.get(position);
        holder.time.setText(s.toString());
    }

    public void add(Schedule item) {
        Integer nbHour = schedulesToDisplay.get(item.hour);
        int position = mDataset.size();
        if(nbHour == null){
            schedulesToDisplay.put(item.hour, 1);
            Log.d(item.toString()+" : 1 span ("+position+")", TAG);
        }
        else{
            nbHour++;
            schedulesToDisplay.put(item.hour, nbHour);
            Log.d(item.toString()+ " : " + nbHour +" spans ("+position+")", TAG);
            if(nbHour > maxSpans){
                maxSpans = nbHour;
            }
        }
        mDataset.add(position, item);
        notifyItemInserted(position);
    }

    public List<Schedule> getDataSet(){
        return mDataset;
    }

    public int getSchedulesToDisplay(int position, GridLayoutManager layoutManager){
        Integer nbHour = schedulesToDisplay.get(mDataset.get(position).hour);
        if(nbHour==null){
            return 0;
        }
        int nbHourInt = nbHour.intValue();
        if( maxSpans%nbHourInt != 0){ // Si la nouvelle ligne n'est pas un multiple de la précédente
            maxSpans = (maxSpans*nbHourInt)/ MathsUtils.pgcd(maxSpans, nbHourInt);
            Log.d("New Max Span "+maxSpans, TAG);
        }
        layoutManager.setSpanCount(maxSpans);
        layoutManager.requestLayout();
        layoutManager.getSpanSizeLookup().invalidateSpanIndexCache();

        Log.d("Span count "+layoutManager.getSpanCount(), TAG);
        Log.d("Heure "+mDataset.get(position).hour+" ("+nbHourInt+") : "+(maxSpans/nbHourInt)+" spans", TAG+" SPAN");
        return (maxSpans/nbHourInt);
    }

    public void removeAll() {
        mDataset.clear();
        schedulesToDisplay.clear();
        maxSpans = 1;
        notifyDataSetChanged();
    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return mDataset.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder{
        // each data item is just a string in this case
        TextView time;
        Schedule scheduleItem;

        public ViewHolder(LinearLayout lyt_main) {
            super(lyt_main);
            time = (TextView) lyt_main.findViewById(R.id.time);
        }

        public void setItem(Schedule item) {
            scheduleItem = item;
        }
    }
}

Every time before downloading new data, the method removeAll() is called from the activity.


回答1:


Actually I solved the problem. I noticed the setSpanSizeLookup method was called only after notifyItemInserted. I have to put my resizes method after.

public void add(Schedule item) {
    Integer nbHour = schedulesToDisplay.get(item.hour);
    int position = mDataset.size();
    if(nbHour == null){
        schedulesToDisplay.put(item.hour, 1);
        Log.d(item.toString()+" : 1 span ("+position+")", TAG);
    }
    else{
        nbHour++;
        schedulesToDisplay.put(item.hour, nbHour);
        Log.d(item.toString()+ " : " + nbHour +" spans ("+position+")", TAG);
        if(nbHour > maxSpans){
            maxSpans = nbHour;
        }
    }
    mDataset.add(position, item);
    notifyItemInserted(position);

    layoutManager.setSpanCount(maxSpans);
    layoutManager.requestLayout();
}


来源:https://stackoverflow.com/questions/28640233/recyclerview-gridlayoutmanager-and-dynamic-spans-count

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!