android - RecyclerView、GridLayoutManager 和动态 Spans 计数

标签 android android-asynctask android-recyclerview

我在 recyclerview 中遇到了一个奇怪的错误。我动态设置跨度并调整跨度大小以适应从 AsyncTask 下载的信息。

有时无法正常显示。看起来好像它显示在屏幕上。!

enter image description here

enter image description here

然后,在一次或多次重新加载后,它会正确显示。 它似乎走出了屏幕,但我不明白为什么。

这是我的适配器:

   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;
        }
    }
}

每次下载新数据之前,都会从 Activity 中调用方法removeAll()。

最佳答案

实际上我已经解决了这个问题。我注意到 setSpanSizeLookup 方法仅在 notificationItemInserted 之后调用。我必须将调整大小方法放在后面。

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();
}

关于android - RecyclerView、GridLayoutManager 和动态 Spans 计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28640233/

相关文章:

android - 如何在 Snackbar 的 RecyclerView.Adapter 中获取 View ?

Android 风格传承

javascript - 如何在android webview中显示javascript弹出窗口

android - 使用 AsyncTask 和 Jsoup 发布 APK 时出错

android - 如何简单地用 RX/Coroutines 替换 android AsyncTask 并返回一个值?

java - 从其他 Activity 中的 AsyncTask 返回值

java - 在我的 FirebaseRecyclerAdapter 方法中,我看不到 populateviewholder 方法未实现

android - 为什么 overScrollBy() 和 onOverScrolled() 不能与 RecyclerView 一起使用

android - Android 启动器上的 float 小部件/覆盖

android - 如何以编程方式在警报对话框的 android 中截取屏幕截图