নেস্টেড রিসাইক্লার দেখার উচ্চতা এর সামগ্রীগুলিকে মোড়া করে না


176

আমার কাছে একটি অ্যাপ্লিকেশন রয়েছে যা বইয়ের সংগ্রহগুলি পরিচালনা করে (প্লেলিস্টগুলির মতো)।

আমি একটি উল্লম্ব পুনর্ব্যবহারযোগ্য ভিউ সহ সংগ্রহের একটি তালিকা এবং প্রতিটি সারির অভ্যন্তরে, একটি অনুভূমিক পুনর্ব্যবহারযোগ্য ভিউতে বইয়ের একটি তালিকা প্রদর্শন করতে চাই।

আমি যখন অভ্যন্তরীণ অনুভূমিক রিসাইক্লারভিউয়ের লেআউট_ উচ্চতাটি 300 ডিপিতে সেট করি তখন এটি সঠিকভাবে প্রদর্শিত হয় তবে যখন আমি এটি মোড়ানো_কন্টেন্টে সেট করি তখন এটি কিছুই প্রদর্শন করে না। আমাকে র‌্যাপ_কন্টেন্টটি ব্যবহার করা প্রয়োজন কারণ আমি উলম্ব এবং অনুভূমিক প্রদর্শনের মধ্যে স্যুইচ করার জন্য প্রোগ্রাম্যালি লেআউট ম্যানেজারটি পরিবর্তন করতে সক্ষম হতে চাই।

এখানে চিত্র বর্ণনা লিখুন

তুমি কি জান আমি কি ভুল করছি?

আমার খণ্ড লেআউট:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/white">

    <com.twibit.ui.view.CustomSwipeToRefreshLayout
        android:id="@+id/swipe_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/shelf_collection_listview"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingTop="10dp"/>

        </LinearLayout>

    </com.twibit.ui.view.CustomSwipeToRefreshLayout>
</LinearLayout>

সংগ্রহের উপাদান বিন্যাস:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:orientation="vertical">

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="#FFF">

        <!-- Simple Header -->

    </RelativeLayout>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="@string/empty_collection"
            android:id="@+id/empty_collection_tv"
            android:visibility="gone"
            android:gravity="center"/>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/collection_book_listview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/> <!-- android:layout_height="300dp" -->

    </FrameLayout>

</LinearLayout>

বইয়ের তালিকা আইটেম:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="180dp"
              android:layout_height="220dp"
              android:layout_gravity="center">

        <ImageView
            android:id="@+id/shelf_item_cover"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:maxWidth="150dp"
            android:maxHeight="200dp"
            android:src="@drawable/placeholder"
            android:contentDescription="@string/cover"
            android:adjustViewBounds="true"
            android:background="@android:drawable/dialog_holo_light_frame"/>

</FrameLayout>

এখানে আমার সংগ্রহ অ্যাডাপ্টারটি রয়েছে:

private class CollectionsListAdapter extends RecyclerView.Adapter<CollectionsListAdapter.ViewHolder> {
    private final String TAG = CollectionsListAdapter.class.getSimpleName();
    private Context mContext;

    // Create the ViewHolder class to keep references to your views
    class ViewHolder extends RecyclerView.ViewHolder {

        private final TextView mHeaderTitleTextView;
        private final TextView mHeaderCountTextView;

        private final RecyclerView mHorizontalListView;
        private final TextView mEmptyTextView;

        public ViewHolder(View view) {
            super(view);

            mHeaderTitleTextView = (TextView) view.findViewById(R.id.collection_header_tv);
            mHeaderCountTextView = (TextView) view.findViewById(R.id.collection_header_count_tv);

            mHorizontalListView = (RecyclerView) view.findViewById(R.id.collection_book_listview);
            mEmptyTextView = (TextView) view.findViewById(R.id.empty_collection_tv);
        }
    }


    public CollectionsListAdapter(Context context) {
        mContext = context;
    }


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int i) {
        Log.d(TAG, "CollectionsListAdapter.onCreateViewHolder(" + parent.getId() + ", " + i + ")");
        // Create a new view by inflating the row item xml.
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.shelf_collection, parent, false);

        // Set the view to the ViewHolder
        ViewHolder holder = new ViewHolder(v);

        holder.mHorizontalListView.setHasFixedSize(false);
        holder.mHorizontalListView.setHorizontalScrollBarEnabled(true);

        // use a linear layout manager
        LinearLayoutManager mLayoutManager = new LinearLayoutManager(mContext);
        mLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        holder.mHorizontalListView.setLayoutManager(mLayoutManager);

        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int i) {
        Log.d(TAG, "CollectionsListAdapter.onBindViewHolder(" + holder.getPosition() + ", " + i + ")");

        Collection collection = mCollectionList.get(i);
        Log.d(TAG, "Collection : " + collection.getLabel());

        holder.mHeaderTitleTextView.setText(collection.getLabel());
        holder.mHeaderCountTextView.setText("" + collection.getBooks().size());

        // Create an adapter if none exists
        if (!mBookListAdapterMap.containsKey(collection.getCollectionId())) {
            mBookListAdapterMap.put(collection.getCollectionId(), new BookListAdapter(getActivity(), collection));
        }

        holder.mHorizontalListView.setAdapter(mBookListAdapterMap.get(collection.getCollectionId()));

    }

    @Override
    public int getItemCount() {
        return mCollectionList.size();
    }
}

এবং অবশেষে, বুক অ্যাডাপ্টার:

private class BookListAdapter extends RecyclerView.Adapter<BookListAdapter.ViewHolder> implements View.OnClickListener {
    private final String TAG = BookListAdapter.class.getSimpleName();

    // Create the ViewHolder class to keep references to your views
    class ViewHolder extends RecyclerView.ViewHolder {
        public ImageView mCoverImageView;

        public ViewHolder(View view) {
            super(view);
            mCoverImageView = (ImageView) view.findViewById(R.id.shelf_item_cover);
        }
    }

    @Override
    public void onClick(View v) {
        BookListAdapter.ViewHolder holder = (BookListAdapter.ViewHolder) v.getTag();
        int position = holder.getPosition();
        final Book book = mCollection.getBooks().get(position);

        // Click on cover image
        if (v.getId() == holder.mCoverImageView.getId()) {
            downloadOrOpenBook(book);
            return;
        }
    }

    private void downloadOrOpenBook(final Book book) {
        // do stuff
    }

    private Context mContext;
    private Collection mCollection;

    public BookListAdapter(Context context, Collection collection) {
        Log.d(TAG, "BookListAdapter(" + context + ", " + collection + ")");
        mCollection = collection;
        mContext = context;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int i) {
        Log.d(TAG, "onCreateViewHolder(" + parent.getId() + ", " + i + ")");
        // Create a new view by inflating the row item xml.
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.shelf_grid_item, parent, false);

        // Set the view to the ViewHolder
        ViewHolder holder = new ViewHolder(v);
        holder.mCoverImageView.setOnClickListener(BookListAdapter.this); // Download or Open

        holder.mCoverImageView.setTag(holder);

        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int i) {
        Log.d(TAG, "onBindViewHolder(" + holder.getPosition() + ", " + i + ")");

        Book book = mCollection.getBooks().get(i);

        ImageView imageView = holder.mCoverImageView;
        ImageLoader.getInstance().displayImage(book.getCoverUrl(), imageView);
    }

    @Override
    public int getItemCount() {
        return mCollection.getBooks().size();
    }
}

উল্লম্ব এবং অনুভূমিকের মধ্যে বিন্যাস ব্যবস্থাপনার পরিবর্তন করতে আপনার মোড়ক_কন্টেন্টটি কেন ব্যবহার করা দরকার?
AmaJayJB

1
যদি আমি বিন্যাস_ উচ্চতা নির্দিষ্ট মানকে সেট করি (অনুভূমিক বিন্যাস পরিচালকের জন্য একটি উপাদানের উচ্চতা বলতে দিন) তবে এটি কেবল উল্লম্ব বিন্যাস ব্যবস্থাপকের সাথে তালিকার প্রথম লাইনটি প্রদর্শন করে।
টুইবিট

তবে রিসাইক্লারভিউতে একটি স্ক্রোলভিউ অন্তর্নির্মিত রয়েছে, যাতে আপনি কেবল আইটেমগুলির মাধ্যমে স্ক্রোল করতে পারেন ... বা আমি কী এখানে বিন্দুটি অনুভব করছি? দুঃখিত বোঝার চেষ্টা করে
AmaJayJB

আমি সংগ্রহ আইটেমগুলির মাধ্যমে স্ক্রোল করতে চাই তবে অভ্যন্তরীণ বইয়ের তালিকাটি নয় (অনুভূমিকভাবে বাদে)। এক্সপেন্ডেবললিস্টভিউয়ের মতো কিছু।
টবিবিট

2
আমি আপনার সাথে একই প্রশ্নের মুখোমুখি, আপনি কি এখন সমাধান করেছেন?
ভিন্সস্টাইলিং

উত্তর:


46

হালনাগাদ

২৩.২.০ সংস্করণে এই বৈশিষ্ট্যটি সম্পর্কিত অনেকগুলি বিষয় 23.2.1 এ স্থির করা হয়েছে, পরিবর্তে সেটিতে আপডেট করুন।

সমর্থন লাইব্রেরি সংস্করণ 23.2 প্রকাশের সাথে, RecyclerViewএখন এটি সমর্থন করে!

আপডেট build.gradleকরুন:

compile 'com.android.support:recyclerview-v7:23.2.1'

বা এর বাইরে যে কোনও সংস্করণ।

এই প্রকাশটি লেআউটম্যানেজার এপিআইতে একটি আকর্ষণীয় নতুন বৈশিষ্ট্য নিয়ে আসে: স্বতঃ-পরিমাপ! এটি কোনও পুনর্ব্যবহারযোগ্য ভিউকে এর সামগ্রীগুলির আকারের ভিত্তিতে নিজেই আকার দিতে দেয় allows এর অর্থ হ'ল পূর্বে অনুপলব্ধ পরিস্থিতি, যেমন রিসাইক্লার ভিউয়ের মাত্রার জন্য Wrap_CONTENT ব্যবহার করা এখন সম্ভব। লেআউট ম্যানেজারে অন্তর্নির্মিত সমস্ত আপনি এখন স্বয়ংক্রিয়-পরিমাপ সমর্থন করে দেখতে পাবেন।

প্রয়োজনে এটি অক্ষম করা setAutoMeasurementEnabled()যেতে পারে। এখানে বিস্তারিত পরীক্ষা করুন


4
সতর্ক হোন! এখানে নতুন বাগ রয়েছে: স্ট্যাকওভারফ্লো
ডেনিস নেক

যে উপরের বাগ ঠিকানা?
razzledazzle

1
এটি সর্বদা সঠিকভাবে কাজ করছে না প্রতিটি আইটেমের মধ্যে ফাঁকা জায়গা দেখতে পাওয়া যায়
রাহুলরস্নিধি

2
সন্তানের পুনর্ব্যবহারযোগ্য ভিউ থাকা প্যারেন্ট লেআউটের উচ্চতাটি সাবধান করুন অবশ্যই সামগ্রী মোড়ানো উচিত must
রাহুলরস্নিধি

2
23.2.1রিসাইক্লারভিউর সংস্করণে বেশ কয়েকটি বাগ স্থির করা হয়েছে বলে মনে হয়। আমাদের জন্য খুব ভাল কাজ করে। যদি তা না হয় তবে আপনি এখানে দিয়েও চেষ্টা করতে পারেন24.0.0-alpha1
জোয়াকুইন ইরচুক

124

@ ব্যবহারকারী2302510 সমাধান আপনার প্রত্যাশার মতো ততটা ভাল কাজ করে না। উভয় অভিমুখীকরণ এবং গতিশীলভাবে ডেটা পরিবর্তনের জন্য সম্পূর্ণ কার্যকারণ হ'ল:

public class MyLinearLayoutManager extends LinearLayoutManager {

    public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout)    {
        super(context, orientation, reverseLayout);
    }

    private int[] mMeasuredDimension = new int[2];

    @Override
    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                          int widthSpec, int heightSpec) {
        final int widthMode = View.MeasureSpec.getMode(widthSpec);
        final int heightMode = View.MeasureSpec.getMode(heightSpec);
        final int widthSize = View.MeasureSpec.getSize(widthSpec);
        final int heightSize = View.MeasureSpec.getSize(heightSpec);
        int width = 0;
        int height = 0;
        for (int i = 0; i < getItemCount(); i++) {
            measureScrapChild(recycler, i,
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    mMeasuredDimension);

            if (getOrientation() == HORIZONTAL) {
                width = width + mMeasuredDimension[0];
                if (i == 0) {
                    height = mMeasuredDimension[1];
                }
            } else {
                height = height + mMeasuredDimension[1];
                if (i == 0) {
                    width = mMeasuredDimension[0];
                }
            }
        }
        switch (widthMode) {
            case View.MeasureSpec.EXACTLY:
                width = widthSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        }

        switch (heightMode) {
            case View.MeasureSpec.EXACTLY:
                height = heightSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        }

        setMeasuredDimension(width, height);
    }

    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                                   int heightSpec, int[] measuredDimension) {
        View view = recycler.getViewForPosition(position);
        if (view != null) {
            RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
            int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                    getPaddingLeft() + getPaddingRight(), p.width);
            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                    getPaddingTop() + getPaddingBottom(), p.height);
            view.measure(childWidthSpec, childHeightSpec);
            measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
            measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
            recycler.recycleView(view);
        }
    }
}

3
আপনার সমাধানটি মোটামুটি ভালভাবে কাজ করে তবে আইটেমডেকারেশন (যেমন বিভাজনকারী) বিবেচনায় নেবে বলে মনে হয় না।
টুইবিট

11
এখনও কেন নিশ্চিত তা নয় তবে স্ক্রোলিংটি কাজ করছে বলে মনে হচ্ছে না। আমি এই কোডটিকে উল্লম্বভাবে স্ক্রোলিং বিন্যাস দিয়ে চেষ্টা করেছি ... আইটেমগুলি যখন পর্দার উচ্চতার চেয়ে কম হয় সবকিছু ঠিকঠাক কাজ করে। যখন স্ক্রিনে প্রদর্শিত হতে পারে তার চেয়েও বেশি আইটেম রয়েছে তখন, স্রোলিং কাজ করে না।
জাস্টিন

1
এটি বিষয়বস্তু পরিবর্তন অ্যানিমেশনগুলির সাথে কাজ করে না - সহজেই বৃদ্ধি / সঙ্কুচিত হওয়ার পরিবর্তে পুনর্ব্যবহারযোগ্য আকারের আকারগুলি।
zyamys


2
আমি এই পুনর্ব্যবহারযোগ্যটি স্ক্রোলভিউয়ের মধ্যে ব্যবহার করছি এবং এই কোডটি ব্যবহার করে পুনর্ব্যবহারযোগ্য মোড়ক সামগ্রী তৈরি করব। তবে স্ক্রোলিং স্ক্রোলভিউটি মসৃণ নয়। সমাধান stackoverflow.com/a/32283439/3736955
Jemshit Iskenderov

39

যখন আপনার আইটেমগুলিকে "র‌্যাপ_কন্টেন্ট" তৈরি করতে হবে তখন উপরের কোডটি ভাল কাজ করে না, কারণ এটি মেচারস্পেক.উনস্পেসফাইড দিয়ে আইটেমের উচ্চতা এবং প্রস্থ উভয়ই পরিমাপ করে। কিছু সমস্যার পরে আমি সেই সমাধানটি পরিবর্তন করেছি যাতে এখন আইটেমগুলি প্রসারিত হতে পারে। পার্থক্যটি হ'ল এটি পিতামাতাদের উচ্চতা বা প্রস্থ প্রদান করে মেজারস্পেক লেআউট ওরিয়েন্টেশনের উপর নির্ভর করে।

public class MyLinearLayoutManager extends LinearLayoutManager {

public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout)    {
    super(context, orientation, reverseLayout);
}

private int[] mMeasuredDimension = new int[2];

@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                      int widthSpec, int heightSpec) {
    final int widthMode = View.MeasureSpec.getMode(widthSpec);
    final int heightMode = View.MeasureSpec.getMode(heightSpec);
    final int widthSize = View.MeasureSpec.getSize(widthSpec);
    final int heightSize = View.MeasureSpec.getSize(heightSpec);
    int width = 0;
    int height = 0;
    for (int i = 0; i < getItemCount(); i++) {


        if (getOrientation() == HORIZONTAL) {

            measureScrapChild(recycler, i,
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    heightSpec,
                    mMeasuredDimension);

            width = width + mMeasuredDimension[0];
            if (i == 0) {
                height = mMeasuredDimension[1];
            }
        } else {
            measureScrapChild(recycler, i,
                    widthSpec,
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    mMeasuredDimension);
            height = height + mMeasuredDimension[1];
            if (i == 0) {
                width = mMeasuredDimension[0];
            }
        }
    }
    switch (widthMode) {
        case View.MeasureSpec.EXACTLY:
            width = widthSize;
        case View.MeasureSpec.AT_MOST:
        case View.MeasureSpec.UNSPECIFIED:
    }

    switch (heightMode) {
        case View.MeasureSpec.EXACTLY:
            height = heightSize;
        case View.MeasureSpec.AT_MOST:
        case View.MeasureSpec.UNSPECIFIED:
    }

    setMeasuredDimension(width, height);
}

private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                               int heightSpec, int[] measuredDimension) {
    View view = recycler.getViewForPosition(position);
    recycler.bindViewToPosition(view, position);
    if (view != null) {
        RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                getPaddingLeft() + getPaddingRight(), p.width);
        int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                getPaddingTop() + getPaddingBottom(), p.height);
        view.measure(childWidthSpec, childHeightSpec);
        measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
        measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
        recycler.recycleView(view);
    }
}
}

ধন্যবাদ! এই সমাধানটি আমার পক্ষে সবচেয়ে ভাল কাজ করেছে। ডেনিস 'যথেষ্ট পরিমাপ করেছে বলে মনে হয় নি এবং দৃশ্যটি এখনও স্ক্রোলযোগ্য। যখন একক শিশু ছিল তখন সিনানের একমাত্র তার আচরণের জন্য সঠিকভাবে উপস্থিত হয়েছিল। দ্রষ্টব্য: আমার সন্তানের মতামত ব্যবহৃত হয়েছেwrap_content
কাসিম

স্ক্রোলিং সক্ষম করার জন্য যখন পিতামাতার সীমারেখাটি হিট হয় তখন আমাকে রাখতে হয়েছিলswitch (heightMode) { case View.MeasureSpec.AT_MOST: if (height < heightSize) break; case View.MeasureSpec.EXACTLY: height = heightSize; case View.MeasureSpec.UNSPECIFIED: }
কাসিম

দুর্দান্ত সমাধান। এটি পুরোপুরি কাজ করে। কনস্ট্রাক্টর ব্যবহার না করে সাইড নোটে, আমি কেবল একটি কনস্ট্যান্ট ফাইনাল ইনটি ওরিয়েন্টেশন (কেবল অন্য কারও সমস্যা দেখা দিচ্ছে) দিয়ে একটি প্রাইভেট ইনস্ট্যান্স ভেরিয়েবল এবং একটি সেটার / গেটর পদ্ধতি তৈরি করেছি এবং তারপরে পাসের দিকনির্দেশ পরীক্ষা করার জন্য এটি ব্যবহার করেছি ।
PGMacDesign

1
আমি ললিপপ এবং তারপরে ইস্যুতে ঝাঁপিয়ে পড়েছি, স্ক্রোলভিউ যা রিসাইক্লারভিউকে ভুলভাবে কাজ করে (যখন কোনও ফ্লিংস নেই) যখন আপনি রিসাইক্লারভিউয়ের উপরে স্ক্রোল করার চেষ্টা করেছিলেন। এই সমস্যাটির সমাধান করার জন্য আপনাকে নোটস্রোললেবলসাইক্লারভিউ (কাস্টম) তৈরি করতে হবে এবং অনারসেপ্টটচ এভেনট, অন টুচেন্ট পদ্ধতিতে সুপার প্রয়োগগুলি কল না করে ওভাররাইড করা উচিত এবং উভয় পদ্ধতিতে আপনার মিথ্যা প্রত্যাবর্তন করা উচিত।
আল্ট্রাসন

এটি কাজ করে তবে আমি বুঝতে পারি না কেন এটি বাচ্চাদের উচ্চতা গণনা করার পরে জিনিসটির উচ্চতা পরিমাপ করা এত অযৌক্তিক জটিল কারণ ...
জো মাহের

22

বিদ্যমান লেআউট ম্যানেজার এখনও মোড়ানো বিষয়বস্তু সমর্থন করে না।

আপনি একটি নতুন লেআউটম্যানেজার তৈরি করতে পারেন যা বিদ্যমানটিকে প্রসারিত করে এবং মোড়ানো সামগ্রীর জন্য পরিমাপ করার জন্য onMeasure পদ্ধতিতে ওভাররাইড করে।


1
এটি আমি প্রত্যাশা করে না তবে এটি সত্য বলে মনে হয়। দেখুন: RecyclerView.LayoutManager & LinearLayoutManager
Twibit

@ হ্যাঁ, রিসাইক্লারভিউ ডিফল্টরূপে মোড়ানো সামগ্রিকে সমর্থন করবে?
সিনান কোজাক

3
এটি রিসাইক্লার ভিউ নয় লেআউট ম্যানেজারের উপর নির্ভর করে। এটি আমাদের রোডম্যাপে রয়েছে।
ইজিগিত

@yigit এই setHasFixedSize(boolean)ডিফল্ট লেআউট পরিচালকদের সাথে বেহুদা রেন্ডার করে না ? যাইহোক, এটি রোডম্যাপে জেনে দুর্দান্ত। আশা করি শিগগিরই এটি বেরিয়ে আসবে।
goncalossilva

হ্যাঁ, কারণ এর আকার অ্যাডাপ্টারের সামগ্রীর উপর নির্ভর করে যদি এলএমের নির্দিষ্ট আকার থাকতে পারে না। মূল পার্থক্যটি হ'ল আরভিটি onMeasure এর আগে বা onLayout এর আগে আপডেটগুলি প্রক্রিয়াকরণ করে। এছাড়াও, আকার পরিবর্তনের সাথে সাথে ভবিষ্যদ্বাণীপূর্ণ অ্যানিমেশনগুলি করা বেশ কঠিন কারণ এলএমের নিজেকে সঠিকভাবে পরিমাপ করার জন্য চূড়ান্ত আকারের জানা থাকা উচিত যখন প্রাক-লেআউটটি পরিমাপের পরে ঘটবে (এটি রিলিং টাইমের মতো)।
ইজিগিত

22

@ Yiğit যেমন উল্লেখ করেছে, আপনাকে onMeasure () টি ওভাররাইড করতে হবে। @ ব্যবহারকারী2302510 এবং @ ডেনিস্নেক উভয়েরই ভাল উত্তর রয়েছে তবে আপনি আইটেমডেকারেশন সমর্থন করতে চাইলে আপনি এই কাস্টম লেআউট ম্যানেজারটি ব্যবহার করতে পারেন।

এবং অন্যান্য উত্তরগুলি স্ক্রিনে প্রদর্শিত হওয়ার চেয়ে বেশি আইটেম থাকা অবস্থায় স্ক্রোল করতে পারে না। স্ক্রিন আকারের চেয়ে বেশি আইটেম থাকা অবস্থায় এই একটি onMeasure () এর ডিফল্ট ইনস্টলমেন্টেশন ব্যবহার করছে।

public class MyLinearLayoutManager extends LinearLayoutManager {

public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout)    {
    super(context, orientation, reverseLayout);
}

private int[] mMeasuredDimension = new int[2];

@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                      int widthSpec, int heightSpec) {
    final int widthMode = View.MeasureSpec.getMode(widthSpec);
    final int heightMode = View.MeasureSpec.getMode(heightSpec);
    final int widthSize = View.MeasureSpec.getSize(widthSpec);
    final int heightSize = View.MeasureSpec.getSize(heightSpec);
    int width = 0;
    int height = 0;
    for (int i = 0; i < getItemCount(); i++) {
        measureScrapChild(recycler, i,
                View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                mMeasuredDimension);

        if (getOrientation() == HORIZONTAL) {
            width = width + mMeasuredDimension[0];
            if (i == 0) {
                height = mMeasuredDimension[1];
            }
        } else {
            height = height + mMeasuredDimension[1];
            if (i == 0) {
                width = mMeasuredDimension[0];
            }
        }
    }

    // If child view is more than screen size, there is no need to make it wrap content. We can use original onMeasure() so we can scroll view.
    if (height < heightSize && width < widthSize) {

        switch (widthMode) {
            case View.MeasureSpec.EXACTLY:
                width = widthSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        }

        switch (heightMode) {
            case View.MeasureSpec.EXACTLY:
                height = heightSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        }

        setMeasuredDimension(width, height);
    } else {
        super.onMeasure(recycler, state, widthSpec, heightSpec);
    }
}

private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                               int heightSpec, int[] measuredDimension) {

   View view = recycler.getViewForPosition(position);

   // For adding Item Decor Insets to view
   super.measureChildWithMargins(view, 0, 0);
    if (view != null) {
        RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                    getPaddingLeft() + getPaddingRight() + getDecoratedLeft(view) + getDecoratedRight(view), p.width);
            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                    getPaddingTop() + getPaddingBottom() + getPaddingBottom() + getDecoratedBottom(view) , p.height);
            view.measure(childWidthSpec, childHeightSpec);

            // Get decorated measurements
            measuredDimension[0] = getDecoratedMeasuredWidth(view) + p.leftMargin + p.rightMargin;
            measuredDimension[1] = getDecoratedMeasuredHeight(view) + p.bottomMargin + p.topMargin;
            recycler.recycleView(view);
        }
    }
}

এবং আপনি যদি গ্রিডলাউটম্যানেজারের সাথে এটি ব্যবহার করতে চান তবে গ্রিডলাউটম্যানেজার থেকে পরিবর্তন করুন এবং পরিবর্তন করুন

for (int i = 0; i < getItemCount(); i++)

প্রতি

for (int i = 0; i < getItemCount(); i = i + getSpanCount())

4
এটি সমাধানটি সঠিকভাবে কাজ করে, আমি এই থ্রেডে অন্য সকলকে পরীক্ষা করেছি এবং তাদের সকলের সমস্যা ছিল
ওয়াইলিল

এই সমাধানটি আমার পক্ষেও খুব ভাল কাজ করেছে। একমাত্র সমস্যা ছিল এটি সন্তানের মোড়ানো পাঠ্যের জন্য সঠিকভাবে অ্যাকাউন্ট করে না। সেই সমস্যার সমাধানের জন্য উপরে আমার উত্তরটি দেখুন।
বিশবুল

এটি গ্রিডলেআউটের জন্য কাজ করে না (হ্যাঁ, আমি পরিবর্তনগুলি প্রয়োগ করেছি)। প্রথমে এটি কাজ করে বলে মনে হচ্ছে, তারপরে আমি ওরিয়েন্টেশনটি পিছনে পিছনে পরিবর্তন করি এবং মূল উচ্চতার তুলনায় উচ্চতা পরিবর্তন করা হয়। এছাড়াও ভিউটি প্রত্যাশিতভাবে আচরণ করে না (উদাহরণস্বরূপ, তারা কাজ করে এমন একটি সাধারণ গ্রিডলেআউটম্যানের সাথে থাকা অনক্লিকগুলি তাদের বেশিরভাগের উপরেই কাজ করে না)।
চিসাবি

আমরা জন্য একই কিভাবে অর্জন করতে পারেন gridlayoutmanagerএবং staggeredgridlayoutmanagerমনে বিঘত গণনা বিবেচনা?
অমৃত বিদ্রি

এই মাইলাইনারলআউটম্যানেজারটি কি শিশু পুনর্ব্যবহারযোগ্য দৃশ্যে বা পিতামাতার কাছে প্রয়োগ করার কথা? অথবা উভয়?
কমনসেন্সকোড

21

মার্চ ২০১ UP আপডেট করুন

একটি সমর্থন লাইব্রেরি সংস্করণের 23.2.1 অ্যান্ড্রয়েড সমর্থন লাইব্রেরি দ্বারা । সুতরাং সমস্ত Wrap_CONTENT টি সঠিকভাবে কাজ করা উচিত।

গ্রেড ফাইলটিতে একটি লাইব্রেরির সংস্করণ আপডেট করুন Please

compile 'com.android.support:recyclerview-v7:23.2.1'

এটি কোনও পুনর্ব্যবহারযোগ্য ভিউকে এর সামগ্রীগুলির আকারের ভিত্তিতে নিজেই আকার দিতে দেয় allows এর অর্থ হ'ল পূর্বে অনুপলব্ধ পরিস্থিতি, যেমন রিসাইক্লার ভিউয়ের মাত্রার জন্য Wrap_CONTENT ব্যবহার করা এখন সম্ভব

আপনাকে সেটআউটমিজার এনেবল (সত্য) কল করতে হবে

আপডেটে বিভিন্ন পরিমাপ-নির্দিষ্ট পদ্ধতিগুলির সাথে সম্পর্কিত বাগগুলি

পরীক্ষা করে দেখুন https://developer.android.com/topic/libraries/support-library/features.html


14

এই উত্তরটি ডেনিস নেক প্রদত্ত সমাধানের ভিত্তিতে তৈরি। এটি ডিভাইডারের মতো সজ্জাটিকে অ্যাকাউন্টে না নেওয়ার সমস্যা সমাধান করে।

public class WrappingRecyclerViewLayoutManager extends LinearLayoutManager {

public WrappingRecyclerViewLayoutManager(Context context)    {
    super(context, VERTICAL, false);
}

public WrappingRecyclerViewLayoutManager(Context context, int orientation, boolean reverseLayout)    {
    super(context, orientation, reverseLayout);
}

private int[] mMeasuredDimension = new int[2];

@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
    final int widthMode = View.MeasureSpec.getMode(widthSpec);
    final int heightMode = View.MeasureSpec.getMode(heightSpec);
    final int widthSize = View.MeasureSpec.getSize(widthSpec);
    final int heightSize = View.MeasureSpec.getSize(heightSpec);
    int width = 0;
    int height = 0;
    for (int i = 0; i < getItemCount(); i++) {
        measureScrapChild(recycler, i,
                View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                mMeasuredDimension);
        if (getOrientation() == HORIZONTAL) {
            width = width + mMeasuredDimension[0];
            if (i == 0) {
                height = mMeasuredDimension[1];
            }
        } else {
            height = height + mMeasuredDimension[1];
            if (i == 0) {
                width = mMeasuredDimension[0];
            }
        }
    }
    switch (widthMode) {
        case View.MeasureSpec.EXACTLY:
            width = widthSize;
        case View.MeasureSpec.AT_MOST:
        case View.MeasureSpec.UNSPECIFIED:
    }

    switch (heightMode) {
        case View.MeasureSpec.EXACTLY:
            height = heightSize;
        case View.MeasureSpec.AT_MOST:
        case View.MeasureSpec.UNSPECIFIED:
    }

    setMeasuredDimension(width, height);
}

private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] measuredDimension) {
    View view = recycler.getViewForPosition(position);
    if (view != null) {
        RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight(), p.width);
        int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom(), p.height);
        view.measure(childWidthSpec, childHeightSpec);
        Rect outRect = new Rect();
        calculateItemDecorationsForChild(view, outRect);
        measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
        measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin + outRect.bottom + outRect.top;
        recycler.recycleView(view);
    }
}

}


1
অবশেষে, একমাত্র জিনিস যা সঠিকভাবে কাজ করে। মহান কাজ. ধন্যবাদ!
falc0nit3

3
আমি java.lang.IndexOutOfBoundsException পেয়ে যাচ্ছি: অবৈধ আইটেমের অবস্থান 0 (0)। আইটেম গণনা: 0 ব্যতিক্রম।
রাহুলআরস্নিধি

9

লেআউটম্যানেজার প্রসারিত করার বিকল্পের জন্য ম্যানুয়ালি কেবলমাত্র আকারের আকার নির্ধারণ করা যেতে পারে।

সারির উচ্চতা প্রতি আইটেমের সংখ্যা (যদি সমস্ত আইটেমের উচ্চতা একই থাকে এবং সারিটিতে পৃথককারী অন্তর্ভুক্ত থাকে)

LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mListView.getLayoutParams();
params.height = mAdapter.getItemCount() * getResources().getDimensionPixelSize(R.dimen.row_height);
mListView.setLayoutParams(params);

এখনও একটি workaround, কিন্তু প্রাথমিক ক্ষেত্রে এটি কাজ করে।


6

এখানে আমি একটি সমাধান পেয়েছি: https://code.google.com/p/android/issues/detail?id=74772

এটি কোনওভাবেই আমার সমাধান নয়। আমি সেখান থেকে কেবল এটি অনুলিপি করেছি, তবে আমি আশা করি যে এটি অনুভূমিক পুনর্ব্যবহারযোগ্য দৃশ্য এবং র‌্যাপ_কন্টেন্ট উচ্চতা বাস্তবায়নের সময় কাউকে যেমন সহায়তা করেছিল ঠিক তেমনভাবে সহায়তা করবে (উল্লম্ব এক এবং মোড়কের_বিস্তার প্রস্থের জন্যও কাজ করা উচিত)

সমাধানটি হ'ল লেআউটম্যানাজারকে প্রসারিত করা এবং @yigit এর পরামর্শ অনুসারে এর onMeasure পদ্ধতি ওভাররাইড করা।

লিঙ্কটি মারা যাওয়ার ক্ষেত্রে কোডটি এখানে:

public static class MyLinearLayoutManager extends LinearLayoutManager {

    public MyLinearLayoutManager(Context context) {
        super(context);
    }

    private int[] mMeasuredDimension = new int[2];

    @Override
    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                          int widthSpec, int heightSpec) {
        final int widthMode = View.MeasureSpec.getMode(widthSpec);
        final int heightMode = View.MeasureSpec.getMode(heightSpec);
        final int widthSize = View.MeasureSpec.getSize(widthSpec);
        final int heightSize = View.MeasureSpec.getSize(heightSpec);

        measureScrapChild(recycler, 0,
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                mMeasuredDimension);

        int width = mMeasuredDimension[0];
        int height = mMeasuredDimension[1];

        switch (widthMode) {
            case View.MeasureSpec.EXACTLY:
            case View.MeasureSpec.AT_MOST:
                width = widthSize;
                break;
            case View.MeasureSpec.UNSPECIFIED:
        }

        switch (heightMode) {
            case View.MeasureSpec.EXACTLY:
            case View.MeasureSpec.AT_MOST:
                height = heightSize;
                break;
            case View.MeasureSpec.UNSPECIFIED:
        }

        setMeasuredDimension(width, height);
    }

    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                                   int heightSpec, int[] measuredDimension) {
        View view = recycler.getViewForPosition(position);
        if (view != null) {
            RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
            int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                    getPaddingLeft() + getPaddingRight(), p.width);
            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                    getPaddingTop() + getPaddingBottom(), p.height);
            view.measure(childWidthSpec, childHeightSpec);
            measuredDimension[0] = view.getMeasuredWidth();
            measuredDimension[1] = view.getMeasuredHeight();
            recycler.recycleView(view);
        }
    }
}

লোটোখেলা! অনুভূমিক দিয়ে নিখুঁতভাবে কাজ করেছেন তবে উল্লম্ব নয়
এইচ রাভাল

5

@ সাইন-কোজাকের সমাধান ব্যবহার করা হয়েছে, কয়েকটি বাগ ব্যতীত। বিশেষত, কল করার সময় আমাদের প্রস্থ এবং উচ্চতা উভয়ই ব্যবহার করা উচিত নয় View.MeasureSpec.UNSPECIFIEDকারণ এটি সন্তানের মোড়ানো পাঠ্যের জন্য যথাযথভাবে অ্যাকাউন্ট নয়। পরিবর্তে, আমরা পিতামাতার কাছ থেকে প্রস্থ এবং উচ্চতা মোডগুলির মধ্য দিয়ে যাব যা জিনিসগুলিকে অনুভূমিক এবং উল্লম্ব উভয় বিন্যাসের জন্য কাজ করতে দেয়।measureScrapChild

public class MyLinearLayoutManager extends LinearLayoutManager {

public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout)    {
    super(context, orientation, reverseLayout);
}

private int[] mMeasuredDimension = new int[2];

@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                      int widthSpec, int heightSpec) {
    final int widthMode = View.MeasureSpec.getMode(widthSpec);
    final int heightMode = View.MeasureSpec.getMode(heightSpec);
    final int widthSize = View.MeasureSpec.getSize(widthSpec);
    final int heightSize = View.MeasureSpec.getSize(heightSpec);
    int width = 0;
    int height = 0;
    for (int i = 0; i < getItemCount(); i++) {    
        if (getOrientation() == HORIZONTAL) {
            measureScrapChild(recycler, i,
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(heightSize, heightMode),
                mMeasuredDimension);

            width = width + mMeasuredDimension[0];
            if (i == 0) {
                height = mMeasuredDimension[1];
            }
        } else {
            measureScrapChild(recycler, i,
                View.MeasureSpec.makeMeasureSpec(widthSize, widthMode),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                mMeasuredDimension);

            height = height + mMeasuredDimension[1];
            if (i == 0) {
                width = mMeasuredDimension[0];
            }
        }
    }

    // If child view is more than screen size, there is no need to make it wrap content. We can use original onMeasure() so we can scroll view.
    if (height < heightSize && width < widthSize) {

        switch (widthMode) {
            case View.MeasureSpec.EXACTLY:
                width = widthSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        }

        switch (heightMode) {
            case View.MeasureSpec.EXACTLY:
                height = heightSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        }

        setMeasuredDimension(width, height);
    } else {
        super.onMeasure(recycler, state, widthSpec, heightSpec);
    }
}

private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                               int heightSpec, int[] measuredDimension) {

   View view = recycler.getViewForPosition(position);

   // For adding Item Decor Insets to view
   super.measureChildWithMargins(view, 0, 0);
    if (view != null) {
        RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                    getPaddingLeft() + getPaddingRight() + getDecoratedLeft(view) + getDecoratedRight(view), p.width);
            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                    getPaddingTop() + getPaddingBottom() + getDecoratedTop(view) + getDecoratedBottom(view) , p.height);
            view.measure(childWidthSpec, childHeightSpec);

            // Get decorated measurements
            measuredDimension[0] = getDecoratedMeasuredWidth(view) + p.leftMargin + p.rightMargin;
            measuredDimension[1] = getDecoratedMeasuredHeight(view) + p.bottomMargin + p.topMargin;
            recycler.recycleView(view);
        }
    }
}

`


আমি পরীক্ষা করেছি এবং এটি কাজ করে, তবে কেবল যদি RecyclerViewএকটিতে বাসা বেধে থাকে LinearLayout। কাজ করে না RelativeLayout
ব্যবহারকারী 2968401

3

হ্যাঁ সমস্ত উত্তরে দেখানো কর্মরূপটি সঠিক, এটি হ'ল চলাকালীন সময়ে চাইল্ড আইটেমগুলির উচ্চতা নির্ধারণের জন্য আমাদের রৈখিক বিন্যাস ব্যবস্থাপককে কাস্টমাইজ করতে হবে। তবে সমস্ত উত্তর প্রত্যাশার মতো কাজ করছে না all সমস্ত ওরিয়েন্টেশন সমর্থন সহ কাস্টম লেআউট ম্যানেজারের জন্য নীচের উত্তরটি দয়া করে করুন।

public class MyLinearLayoutManager extends android.support.v7.widget.LinearLayoutManager {

private static boolean canMakeInsetsDirty = true;
private static Field insetsDirtyField = null;

private static final int CHILD_WIDTH = 0;
private static final int CHILD_HEIGHT = 1;
private static final int DEFAULT_CHILD_SIZE = 100;

private final int[] childDimensions = new int[2];
private final RecyclerView view;

private int childSize = DEFAULT_CHILD_SIZE;
private boolean hasChildSize;
private int overScrollMode = ViewCompat.OVER_SCROLL_ALWAYS;
private final Rect tmpRect = new Rect();

@SuppressWarnings("UnusedDeclaration")
public MyLinearLayoutManager(Context context) {
    super(context);
    this.view = null;
}

@SuppressWarnings("UnusedDeclaration")
public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
    super(context, orientation, reverseLayout);
    this.view = null;
}

@SuppressWarnings("UnusedDeclaration")
public MyLinearLayoutManager(RecyclerView view) {
    super(view.getContext());
    this.view = view;
    this.overScrollMode = ViewCompat.getOverScrollMode(view);
}

@SuppressWarnings("UnusedDeclaration")
public MyLinearLayoutManager(RecyclerView view, int orientation, boolean reverseLayout) {
    super(view.getContext(), orientation, reverseLayout);
    this.view = view;
    this.overScrollMode = ViewCompat.getOverScrollMode(view);
}

public void setOverScrollMode(int overScrollMode) {
    if (overScrollMode < ViewCompat.OVER_SCROLL_ALWAYS || overScrollMode > ViewCompat.OVER_SCROLL_NEVER)
        throw new IllegalArgumentException("Unknown overscroll mode: " + overScrollMode);
    if (this.view == null) throw new IllegalStateException("view == null");
    this.overScrollMode = overScrollMode;
    ViewCompat.setOverScrollMode(view, overScrollMode);
}

public static int makeUnspecifiedSpec() {
    return View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
}

@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
    final int widthMode = View.MeasureSpec.getMode(widthSpec);
    final int heightMode = View.MeasureSpec.getMode(heightSpec);

    final int widthSize = View.MeasureSpec.getSize(widthSpec);
    final int heightSize = View.MeasureSpec.getSize(heightSpec);

    final boolean hasWidthSize = widthMode != View.MeasureSpec.UNSPECIFIED;
    final boolean hasHeightSize = heightMode != View.MeasureSpec.UNSPECIFIED;

    final boolean exactWidth = widthMode == View.MeasureSpec.EXACTLY;
    final boolean exactHeight = heightMode == View.MeasureSpec.EXACTLY;

    final int unspecified = makeUnspecifiedSpec();

    if (exactWidth && exactHeight) {
        // in case of exact calculations for both dimensions let's use default "onMeasure" implementation
        super.onMeasure(recycler, state, widthSpec, heightSpec);
        return;
    }

    final boolean vertical = getOrientation() == VERTICAL;

    initChildDimensions(widthSize, heightSize, vertical);

    int width = 0;
    int height = 0;

    // it's possible to get scrap views in recycler which are bound to old (invalid) adapter entities. This
    // happens because their invalidation happens after "onMeasure" method. As a workaround let's clear the
    // recycler now (it should not cause any performance issues while scrolling as "onMeasure" is never
    // called whiles scrolling)
    recycler.clear();

    final int stateItemCount = state.getItemCount();
    final int adapterItemCount = getItemCount();
    // adapter always contains actual data while state might contain old data (f.e. data before the animation is
    // done). As we want to measure the view with actual data we must use data from the adapter and not from  the
    // state
    for (int i = 0; i < adapterItemCount; i++) {
        if (vertical) {
            if (!hasChildSize) {
                if (i < stateItemCount) {
                    // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items
                    // we will use previously calculated dimensions
                    measureChild(recycler, i, widthSize, unspecified, childDimensions);
                } else {
                    logMeasureWarning(i);
                }
            }
            height += childDimensions[CHILD_HEIGHT];
            if (i == 0) {
                width = childDimensions[CHILD_WIDTH];
            }
            if (hasHeightSize && height >= heightSize) {
                break;
            }
        } else {
            if (!hasChildSize) {
                if (i < stateItemCount) {
                    // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items
                    // we will use previously calculated dimensions
                    measureChild(recycler, i, unspecified, heightSize, childDimensions);
                } else {
                    logMeasureWarning(i);
                }
            }
            width += childDimensions[CHILD_WIDTH];
            if (i == 0) {
                height = childDimensions[CHILD_HEIGHT];
            }
            if (hasWidthSize && width >= widthSize) {
                break;
            }
        }
    }

    if (exactWidth) {
        width = widthSize;
    } else {
        width += getPaddingLeft() + getPaddingRight();
        if (hasWidthSize) {
            width = Math.min(width, widthSize);
        }
    }

    if (exactHeight) {
        height = heightSize;
    } else {
        height += getPaddingTop() + getPaddingBottom();
        if (hasHeightSize) {
            height = Math.min(height, heightSize);
        }
    }

    setMeasuredDimension(width, height);

    if (view != null && overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS) {
        final boolean fit = (vertical && (!hasHeightSize || height < heightSize))
                || (!vertical && (!hasWidthSize || width < widthSize));

        ViewCompat.setOverScrollMode(view, fit ? ViewCompat.OVER_SCROLL_NEVER : ViewCompat.OVER_SCROLL_ALWAYS);
    }
}

private void logMeasureWarning(int child) {
    if (BuildConfig.DEBUG) {
        Log.w("MyLinearLayoutManager", "Can't measure child #" + child + ", previously used dimensions will be reused." +
                "To remove this message either use #setChildSize() method or don't run RecyclerView animations");
    }
}

private void initChildDimensions(int width, int height, boolean vertical) {
    if (childDimensions[CHILD_WIDTH] != 0 || childDimensions[CHILD_HEIGHT] != 0) {
        // already initialized, skipping
        return;
    }
    if (vertical) {
        childDimensions[CHILD_WIDTH] = width;
        childDimensions[CHILD_HEIGHT] = childSize;
    } else {
        childDimensions[CHILD_WIDTH] = childSize;
        childDimensions[CHILD_HEIGHT] = height;
    }
}

@Override
public void setOrientation(int orientation) {
    // might be called before the constructor of this class is called
    //noinspection ConstantConditions
    if (childDimensions != null) {
        if (getOrientation() != orientation) {
            childDimensions[CHILD_WIDTH] = 0;
            childDimensions[CHILD_HEIGHT] = 0;
        }
    }
    super.setOrientation(orientation);
}

public void clearChildSize() {
    hasChildSize = false;
    setChildSize(DEFAULT_CHILD_SIZE);
}

public void setChildSize(int childSize) {
    hasChildSize = true;
    if (this.childSize != childSize) {
        this.childSize = childSize;
        requestLayout();
    }
}

private void measureChild(RecyclerView.Recycler recycler, int position, int widthSize, int heightSize, int[] dimensions) {
    final View child;
    try {
        child = recycler.getViewForPosition(position);
    } catch (IndexOutOfBoundsException e) {
        if (BuildConfig.DEBUG) {
            Log.w("MyLinearLayoutManager", "MyLinearLayoutManager doesn't work well with animations. Consider switching them off", e);
        }
        return;
    }

    final RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) child.getLayoutParams();

    final int hPadding = getPaddingLeft() + getPaddingRight();
    final int vPadding = getPaddingTop() + getPaddingBottom();

    final int hMargin = p.leftMargin + p.rightMargin;
    final int vMargin = p.topMargin + p.bottomMargin;

    // we must make insets dirty in order calculateItemDecorationsForChild to work
    makeInsetsDirty(p);
    // this method should be called before any getXxxDecorationXxx() methods
    calculateItemDecorationsForChild(child, tmpRect);

    final int hDecoration = getRightDecorationWidth(child) + getLeftDecorationWidth(child);
    final int vDecoration = getTopDecorationHeight(child) + getBottomDecorationHeight(child);

    final int childWidthSpec = getChildMeasureSpec(widthSize, hPadding + hMargin + hDecoration, p.width, canScrollHorizontally());
    final int childHeightSpec = getChildMeasureSpec(heightSize, vPadding + vMargin + vDecoration, p.height, canScrollVertically());

    child.measure(childWidthSpec, childHeightSpec);

    dimensions[CHILD_WIDTH] = getDecoratedMeasuredWidth(child) + p.leftMargin + p.rightMargin;
    dimensions[CHILD_HEIGHT] = getDecoratedMeasuredHeight(child) + p.bottomMargin + p.topMargin;

    // as view is recycled let's not keep old measured values
    makeInsetsDirty(p);
    recycler.recycleView(child);
}

private static void makeInsetsDirty(RecyclerView.LayoutParams p) {
    if (!canMakeInsetsDirty) {
        return;
    }
    try {
        if (insetsDirtyField == null) {
            insetsDirtyField = RecyclerView.LayoutParams.class.getDeclaredField("mInsetsDirty");
            insetsDirtyField.setAccessible(true);
        }
        insetsDirtyField.set(p, true);
    } catch (NoSuchFieldException e) {
        onMakeInsertDirtyFailed();
    } catch (IllegalAccessException e) {
        onMakeInsertDirtyFailed();
    }
}

private static void onMakeInsertDirtyFailed() {
    canMakeInsetsDirty = false;
    if (BuildConfig.DEBUG) {
        Log.w("MyLinearLayoutManager", "Can't make LayoutParams insets dirty, decorations measurements might be incorrect");
    }
}
}

3

অ্যান্ড্রয়েড সহায়তা লাইব্রেরি এখন Wrap_CONTENT সম্পত্তিও পরিচালনা করে। এটি কেবল আপনার গ্রেডে আমদানি করুন।

compile 'com.android.support:recyclerview-v7:23.2.0'

আর হয়ে গেল!


2

ডেনিস নেকের কাজের ভিত্তিতে, আইটেমের প্রস্থের যোগফল ধারকের আকারের চেয়ে কম হলে এটি ভাল কাজ করে। তা ছাড়া, এটি পুনর্ব্যবহারযোগ্য পর্যালোচনাটি অ স্ক্রোলযোগ্য করে তুলবে এবং কেবলমাত্র ডেটা উপসেট দেখায় show

এই সমস্যাটি সমাধান করার জন্য, আমি সমাধানটি অ্যালিটালটি সংশোধন করেছিলাম যাতে এটি সরবরাহিত আকারের এবং গণিত আকারের নূন্যতম চয়ন করে। নিচে দেখ:

package com.linkdev.gafi.adapters;

import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;

import com.linkdev.gafi.R;

public class MyLinearLayoutManager extends LinearLayoutManager {

    public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout)    {
        super(context, orientation, reverseLayout);
        this.c = context;
    }


    private Context c;
    private int[] mMeasuredDimension = new int[2];


    @Override
    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                          int widthSpec, int heightSpec) {
        final int widthMode = View.MeasureSpec.getMode(widthSpec);
        final int heightMode = View.MeasureSpec.getMode(heightSpec);
        final int widthSize = View.MeasureSpec.getSize(widthSpec);
        final int heightSize = View.MeasureSpec.getSize(heightSpec);



        int width = 0;
        int height = 0;
        for (int i = 0; i < getItemCount(); i++) {
            measureScrapChild(recycler, i,
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    mMeasuredDimension);

            if (getOrientation() == HORIZONTAL) {
                width = width + mMeasuredDimension[0];
                if (i == 0) {
                    height = mMeasuredDimension[1];
                }
            } else {
                height = height + mMeasuredDimension[1];
                if (i == 0) {
                    width = mMeasuredDimension[0];
                }
            }
        }


        switch (widthMode) {
            case View.MeasureSpec.EXACTLY:
                width = widthSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        }

        switch (heightMode) {
            case View.MeasureSpec.EXACTLY:
                height = heightSize;
            case View.MeasureSpec.AT_MOST:
            case View.MeasureSpec.UNSPECIFIED:
        }

        int widthDesired = Math.min(widthSize,width);
        setMeasuredDimension(widthDesired, height);
    }

    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                                   int heightSpec, int[] measuredDimension) {
        View view = recycler.getViewForPosition(position);
        if (view != null) {
            RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
            int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                    getPaddingLeft() + getPaddingRight(), p.width);
            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                    getPaddingTop() + getPaddingBottom(), p.height);
            view.measure(childWidthSpec, childHeightSpec);
            measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
            measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
            recycler.recycleView(view);
        }
    }}

1

আমি সমস্ত সমাধান চেষ্টা করেছি, সেগুলি খুব দরকারী তবে এটি কেবল আমার পক্ষে কাজ করে

public class  LinearLayoutManager extends android.support.v7.widget.LinearLayoutManager {

    public LinearLayoutManager(Context context, int orientation, boolean reverseLayout)    {
        super(context, orientation, reverseLayout);
    }

    private int[] mMeasuredDimension = new int[2];

    @Override
    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                          int widthSpec, int heightSpec) {
        final int widthMode = View.MeasureSpec.getMode(widthSpec);
        final int heightMode = View.MeasureSpec.getMode(heightSpec);
        final int widthSize = View.MeasureSpec.getSize(widthSpec);
        final int heightSize = View.MeasureSpec.getSize(heightSpec);
        int width = 0;
        int height = 0;
        for (int i = 0; i < getItemCount(); i++) {


            if (getOrientation() == HORIZONTAL) {

                measureScrapChild(recycler, i,
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                        heightSpec,
                        mMeasuredDimension);

                width = width + mMeasuredDimension[0];
                if (i == 0) {
                    height = mMeasuredDimension[1];
                }
            } else {
                measureScrapChild(recycler, i,
                        widthSpec,
                        View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                        mMeasuredDimension);
                height = height + mMeasuredDimension[1];
                if (i == 0) {
                    width = mMeasuredDimension[0];
                }
            }
        }

        if (height < heightSize || width < widthSize) {

            switch (widthMode) {
                case View.MeasureSpec.EXACTLY:
                    width = widthSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }

            switch (heightMode) {
                case View.MeasureSpec.EXACTLY:
                    height = heightSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }

            setMeasuredDimension(width, height);
        } else {
            super.onMeasure(recycler, state, widthSpec, heightSpec);
        }
    }

    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                                   int heightSpec, int[] measuredDimension) {
        View view = recycler.getViewForPosition(position);
        recycler.bindViewToPosition(view, position);
        if (view != null) {
            RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
            int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                    getPaddingLeft() + getPaddingRight(), p.width);
            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                    getPaddingTop() + getPaddingBottom(), p.height);
            view.measure(childWidthSpec, childHeightSpec);
            measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
            measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
            recycler.recycleView(view);
        }
    }
}

0

গ্রিড লেআউটটির সাহায্যে কেবল রিসাইক্লার ভিউ ব্যবহার করে সামগ্রীটি মোড়ানো

চিত্র: গ্রিডভিউ লেআউট হিসাবে পুনর্ব্যবহারকারী

গ্রিডলআউটআউট ম্যানেজারটি কেবল এটির মতো ব্যবহার করুন:

RecyclerView.LayoutManager mRecyclerGrid=new GridLayoutManager(this,3,LinearLayoutManager.VERTICAL,false);
mRecyclerView.setLayoutManager(mRecyclerGrid);

কতগুলি আইটেম একটি সারিতে প্রদর্শিত হবে তা আপনি সেট করতে পারেন (3 প্রতিস্থাপন করুন)।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.