Android RecyclerView: изменить LIST файла макета на GRID onOptionItemSelected

Я разрабатываю приложение для Android для интернет-магазинов. Я создал следующее представление для списка продуктов, используя RecyclerView, поскольку я хочу изменить представление при выборе пункта меню параметров:

Я создал следующий адаптер с именем ProductAdapter, в котором я реализовал код для изменения макета в onCreateViewHolder для выбора файла макета на основе логического значения.

Код адаптера ProductAdapter:

    /***
     * ADAPTER for Product to binding rows in List
     */
    private class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ProductRowHolder> {

        private List<Product> productList;

        private Context mContext;

        public ProductAdapter(Context context, List<Product> feedItemList) {
            this.productList = feedItemList;
            this.mContext = context;
        }

        @Override
        public ProductRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
            View v = LayoutInflater.from(viewGroup.getContext()).inflate(isProductViewAsList ? R.layout.product_row_layout_list : R.layout.product_row_layout_grid, null);
            ProductRowHolder mh = new ProductRowHolder(v);
            return mh;
        }

        @Override
        public void onBindViewHolder(ProductRowHolder  productRowHolder, int i) {
            Product prodItem = productList.get(i);

//            Picasso.with(mContext).load(feedItem.getName())
//                    .error(R.drawable.ic_launcher)
//                    .placeholder(R.drawable.ic_launcher)
//                    .into(productRowHolder.thumbnail);


            double price = prodItem.getPrice();
            double discount = prodItem.getDiscount();
            double discountedPrice = price - (price * discount / 100);

            String code = "";
            if(prodItem.getCode() != null)
                code = "[" + prodItem.getCode() + "] ";

            productRowHolder.prodIsNewView.setVisibility(prodItem.getIsNew() == 1 ? View.VISIBLE : View.INVISIBLE);
            productRowHolder.prodNameView.setText(code + prodItem.getName());
            productRowHolder.prodOriginalRateView.setText("Rs." + new BigDecimal(price).setScale(2,RoundingMode.DOWN));
            productRowHolder.prodDiscView.setText("" + new BigDecimal(discount).setScale(2,RoundingMode.DOWN) + "% off");
            productRowHolder.prodDiscRateView.setText("Rs." + new BigDecimal(discountedPrice).setScale(2,RoundingMode.DOWN));

            productRowHolder.prodOriginalRateView.setPaintFlags(productRowHolder.prodOriginalRateView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
        }

        @Override
        public int getItemCount() {
            return (null != productList ? productList.size() : 0);
        }

        public class ProductRowHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
            //Declaration of Views

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

                view.setOnClickListener(this);

                //Find Views
            }

            @Override
            public void onClick(View view) {
               //Onclick of row
            }
        }
    }

После этого я сделал код для изменения макета RecyclerView с List на Grid и наоборот в onOptionsItemSelected, здесь я вызываю mAdapter.notifyDataSetChanged();, поэтому он снова вызовет адаптер и изменит значение.

onOptionsItemSelected:

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        switch (id) {
            case R.id.action_settings:
                return true;
            case android.R.id.home:
                finish();
                break;
            case R.id.product_show_as_view:
                isProductViewAsList = !isProductViewAsList;
                supportInvalidateOptionsMenu();
                mRecyclerView.setLayoutManager(isProductViewAsList ? new LinearLayoutManager(this) : new GridLayoutManager(this, 2));
                mAdapter.notifyDataSetChanged();
                break;
        }

        return super.onOptionsItemSelected(item);
    }

Я добился небольшого успеха, например:

Изображение макета Grid:

введите здесь описание изображения

Изображение макета List:

введите здесь описание изображения

НО ТЕПЕРЬ, КОГДА Я ПРОКРУТЫВАЮ, а затем отображается ИЗМЕНЕНИЕ ВИДА, например:

Grid макет:

введите здесь описание изображения

List макет:

введите здесь описание изображения

Я не знаю, почему это происходит после прокрутки. Есть ли другой способ изменить представление, подобное этому?

Сегодня я только что увидел, что эта проблема из-за ImageView, без него все работает отлично.

Помогите пожалуйста, Ваша помощь будет оценена по достоинству.


person Pratik Butani    schedule 18.02.2015    source источник
comment
Этот ответ может помочь: stackoverflow.com/a/24933117/2649012   -  person Phantômaxx    schedule 18.02.2015
comment
используйте этот RecyclerView.setHasFixedSize(true);   -  person Amrut Bidri    schedule 26.02.2015
comment
это mRecyclerView.setHasFixedSize(true);, но у меня не работает. любое другое решение?   -  person Pratik Butani    schedule 26.02.2015
comment
Я думаю, что этот ответ может вам помочь: RecyclerView: как очистить кешированные/переработанные представления?   -  person Luciano    schedule 14.03.2015
comment
вы уже решили это?   -  person Bojan Kseneman    schedule 25.04.2015
comment
Я разместил свое решение как ответ @Harsha   -  person Pratik Butani    schedule 24.09.2015
comment
Мне нужно еще какое-то объяснение, почему, потому что я новичок в Android Studio. Как добавить эти значки списка или сетки, значки меню опций, как сделать видимыми и невидимыми значки параметров, и все это в Android Navigation Drawer с видом домашнего фрагмента. Этот значок элементов параметров справа посередине экрана. как изменить панель инструментов для отдельного фрагмента также возможно ли вместе с ящиком   -  person Harsha    schedule 24.09.2015
comment
Ох. Так что я должен все объяснить, а это невозможно на #SO @Harsha   -  person Pratik Butani    schedule 24.09.2015
comment
о, не проблема, можете ли вы предоставить какие-либо справочные ссылки для лучшего понимания. Я не хочу беспокоить. Я планирую разработать приложение для Android на телугу, например, для этих значков optionitem. Спасибо   -  person Harsha    schedule 24.09.2015
comment
как разместить эти элементы списка и сетки и как изменить значки из menu.xml с видимыми ушедшими свойствами или любым другим, пожалуйста, помогите мне   -  person Harsha    schedule 30.01.2016
comment
developer.android.com/intl/es/guide/topics/ ui/menus.html @Харша   -  person Pratik Butani    schedule 30.01.2016
comment
привет pratik, пожалуйста, не могли бы вы опубликовать этот метод меню параметров, а также образец фрагмента списка и сетки, пожалуйста, помогите мне.   -  person Harsha    schedule 01.02.2016
comment
привет, я могу изменить данные представления списка и сетки, когда пользователь щелкнул значок меню параметров, но как заменить список значками сетки и списка   -  person Harsha    schedule 01.02.2016
comment
stackoverflow.com/a/20614728/1318946 @Harsha   -  person Pratik Butani    schedule 01.02.2016
comment
спасибо всем, кто предоставил образцы ссылок и дал некоторую ценную информацию. наконец, добился этого. изменение значка меню параметров и просмотров сетки списка. но как заменить сетку макетом костюма.   -  person Harsha    schedule 16.02.2016
comment
setLayoutManager (isProductViewAsList? новый LinearLayoutManager (этот): новый GridLayoutManager (это, 2)); здесь нам нужно установить удобное расположение строк сетки   -  person Harsha    schedule 16.02.2016
comment
@PratikButani Не могли бы вы рассказать мне isProductViewAsList об этой переменной и где ее объявить? или вы можете отправить мне полный код.   -  person Google    schedule 16.06.2016


Ответы (5)


Я нашел решение с запуском активности, которую я установил LinearLayoutManager, например:

mLayoutManager = new LinearLayoutManager(this);
mProductListRecyclerView.setLayoutManager(mLayoutManager);

после этого onOptionsItemSelected пишется так:

case R.id.menu_product_change_view:
     isViewWithCatalog = !isViewWithCatalog;
     supportInvalidateOptionsMenu();
     //loading = false;
     mProductListRecyclerView.setLayoutManager(isViewWithCatalog ? new LinearLayoutManager(this) : new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
     mProductListRecyclerView.setAdapter(mAdapter);
     break;

и изменить вид в onCreateViewHolder, например:

@Override
public ProductRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View v = LayoutInflater.from(viewGroup.getContext()).inflate(isViewWithCatalog ? R.layout.product_row_layout_list : R.layout.product_row_layout_grid, null);
    ProductRowHolder mh = new ProductRowHolder(v);
    return mh;
}

От начала до конца вы должны управлять переменной isViewWithCatalog для отображения макета первым.

person Pratik Butani    schedule 26.02.2015
comment
Что такое isViewWithCatalog как это получить? - person Ramesh sambu; 13.01.2018
comment
@R2R isViewWithCatalog — это логическая переменная, определенная в этом действии, которая будет решать, какой макет будет первым. - person Pratik Butani; 13.01.2018
comment
Я бы скорее использовал здесь шаблон стратегии! - person Skynet; 26.11.2018
comment
@Skynet Как вы будете использовать здесь шаблон стратегии? - person Sumit Shukla; 13.02.2019
comment
isViewWithCatalog также определяется в адаптере! - person Sava Dimitrijević; 19.02.2019
comment
Да, это я передал в аргументе конструктора. @СаваДимитриевич - person Pratik Butani; 19.02.2019
comment
Это имеет смысл. Спасибо за ответ! - person Sava Dimitrijević; 19.02.2019
comment
Спасибо за ваш голос: теперь вопросы и ответы равны 32:32: D @SavaDimitrijević - person Pratik Butani; 19.02.2019
comment
@pratik-butani, не могли бы вы обновить свой ответ с помощью полного конструктора адаптера? и как вы передаете эту переменную isViewWithCatalog в MainActivity? - person Dr Mido; 15.03.2019

В этих примерах SDK есть полный пример, однако он использует один файл макета для обоих LayoutManagers

Для сохранения позиции прокрутки при переключении раскладки они использовали эту функцию

public void setRecyclerViewLayoutManager(LayoutManagerType layoutManagerType) {
    int scrollPosition = 0;

    // If a layout manager has already been set, get current scroll position.
    if (mRecyclerView.getLayoutManager() != null) {
        scrollPosition = ((LinearLayoutManager) mRecyclerView.getLayoutManager())
                .findFirstCompletelyVisibleItemPosition();
    }

    switch (layoutManagerType) {
        case GRID_LAYOUT_MANAGER:
            mLayoutManager = new GridLayoutManager(getActivity(), SPAN_COUNT);
            mCurrentLayoutManagerType = LayoutManagerType.GRID_LAYOUT_MANAGER;
            break;
        case LINEAR_LAYOUT_MANAGER:
            mLayoutManager = new LinearLayoutManager(getActivity());
            mCurrentLayoutManagerType = LayoutManagerType.LINEAR_LAYOUT_MANAGER;
            break;
        default:
            mLayoutManager = new LinearLayoutManager(getActivity());
            mCurrentLayoutManagerType = LayoutManagerType.LINEAR_LAYOUT_MANAGER;
    }

    mRecyclerView.setLayoutManager(mLayoutManager);
    mRecyclerView.scrollToPosition(scrollPosition);
}
person Mohammad Yahia    schedule 19.10.2016
comment
Я знаю, что с момента этого ответа прошло много времени, я вижу, что текущая страница примера не найдена, пожалуйста, если есть полный пример, сообщите мне - person Dr Mido; 17.03.2019
comment
см. этот android.googlesource.com/platform/development/+/77b5d39/samples/ - person Mohammad Yahia; 17.03.2019

Я решил эту проблему, снова установив адаптер на RecyclerView после смены менеджера компоновки.

listView.setLayoutManager(new LinearLayoutManager(this));
listView.setAdapter(adapter);
person Alessandro Roaro    schedule 22.05.2015
comment
После прокрутки до 30-40 элементов, а затем, если я попытаюсь изменить вид, он снова начнется с 1 позиции для прокрутки. Есть ли какое-нибудь решение для этого? - person Pratik Butani; 01.09.2015
comment
@PratikButani, попробуйте использовать recyclerView.scrollToPosition(position); после установки нового LayoutManager. - person Haresh Chhelana; 24.09.2015
comment
как я могу восстановить положение адаптера? Я думаю о создании метода, который сохраняет последнюю позицию, полученную с помощью onBindViewHolder, но все же думаю, что есть лучший способ - person crgarridos; 05.08.2016

Я думаю, что после прокрутки и возврата к сетке первый элемент не воссоздается. Я решил это, переопределив getItemViewType() и соответственно раздув файлы макета в onCreateViewHolder.

person user3377402    schedule 27.10.2015

Я использую ViewFlipper и изменяю тип отображения списка с анимацией. и красивая .

в основном xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>

<ViewFlipper android:id="@+id/view_flipper"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.v7.widget.RecyclerView 
        android:id="@+id/small_list"   android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:overScrollMode="never" />
    <android.support.v7.widget.RecyclerView android:scrollbarStyle="insideInset"
        android:id="@+id/big_list"  android:scrollbars="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:overScrollMode="never" />
    <android.support.v7.widget.RecyclerView android:scrollbarStyle="insideInset"
        android:id="@+id/grid_list" android:paddingLeft="2.0dip" android:paddingRight="2.0dip" android:layout_width="match_parent" android:layout_height="match_parent" android:overScrollMode="never" />
</ViewFlipper>

all code in activity

    private RecyclerView smallRecycleView;
private RecyclerView gridRecycleView;
private RecyclerView bigRecycleView;

private StaggeredGridLayoutManager gridLayoutManager;
private LinearLayoutManager bigLayoutManager;
private LinearLayoutManager smallLayoutManager;

private AAdapter adapterGrid;
private AAdapter adapterSmall;
private AAdapter adapterBig;

private ViewFlipper viewFlipper;


private TypeShow typeShowList = TypeShow.Small;


private AList list = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    setLayout( R.layout.main_layout);
    super.onCreate(savedInstanceState);

    try {

        list = getItems(10);


        viewFlipper = ((ViewFlipper)findViewById(R.id.view_flipper));
        viewFlipper.setOutAnimation(MainActivity.this, R.anim.anim_fade_out_flip);
        viewFlipper.setInAnimation(MainActivity.this, R.anim.anim_fade_in_flip);

        smallRecycleView = ((RecyclerView)findViewById(R.id.small_list));
        gridRecycleView = ((RecyclerView)findViewById(R.id.grid_list));
        bigRecycleView = ((RecyclerView)findViewById(R.id.big_list));

        smallRecycleView.setHasFixedSize(false);
        gridRecycleView.setHasFixedSize(false);
        bigRecycleView.setHasFixedSize(false);

        smallLayoutManager = new LinearLayoutManager(MainActivity.this);
        smallRecycleView.setLayoutManager(smallLayoutManager);
        gridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
        gridRecycleView.setLayoutManager(gridLayoutManager);
        gridRecycleView.setItemAnimator(null);
        bigLayoutManager = new LinearLayoutManager(MainActivity.this);
        bigRecycleView.setLayoutManager(bigLayoutManager);


        adapterSmall = new AAdapter(MainActivity.this,list,MainActivity.this,TypeShow.Small);
        smallRecycleView.setAdapter(adapterSmall);

        adapterGrid = new AAdapter(MainActivity.this,list,MainActivity.this,TypeShow.Grid);
        gridRecycleView.setAdapter(adapterGrid);

        adapterBig = new AAdapter(MainActivity.this,list,MainActivity.this,TypeShow.Big);
        bigRecycleView.setAdapter(adapterBig);





        if (Build.VERSION.SDK_INT >= 11)
        {
            smallRecycleView.setVerticalScrollbarPosition(1);
            gridRecycleView.setVerticalScrollbarPosition(1);
            bigRecycleView.setVerticalScrollbarPosition(1);
        }

        final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.floating_action_button);
               fab.setOnClickListener(new View.OnClickListener() {
                       @Override
                       public void onClick(View view) {
                           smallRecycleView.setSelected(false);
                           bigRecycleView.setSelected(false);
                           gridRecycleView.setSelected(false);
                           viewFlipper.showNext();

                           if(typeShowList == TypeShow.Small){
                               typeShowList = TypeShow.Big;
                               fab.setImageResource(R.drawable.ic_type_grid);
                           }
                           else if(typeShowList == TypeShow.Big){
                               typeShowList = TypeShow.Grid;
                               fab.setImageResource(R.drawable.ic_atype_small);
                           }
                           else {
                               typeShowList = TypeShow.Small;
                               fab.setImageResource(R.drawable.ic_type_big);
                           }
                        }
               });
        fab.setImageResource(R.drawable.ic_type_big);

    }
    catch (Exception e){
    }
}

тип

public enum TypeShow {
Grid,
Small,
Big }

адаптер

public class AAdapter extends RecyclerView.Adapter<AAdapter.PersonViewHolder> {

private AList noteList = null;
private MainActivity mContext;
private TypeShow typeShow; 

public AAdapter(MainActivity mContext, AList noteList, OnItemClickListener mListener, TypeShow typeShow){
    this.noteList = noteList;
    this.mContext= mContext;
    this.mListener= mListener;
    this.typeShow= typeShow; 
}

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

@Override
public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    if(typeShow == TypeShow.Grid) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.activity_row_grid, viewGroup, false);
        return new PersonViewHolder(v);
    }
    else if(typeShow == TypeShow.Small) {

        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.activity_row_small, viewGroup, false);
        return new PersonViewHolder(v);
    }
    else {  
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.activity_row_big, viewGroup, false);
        return new PersonViewHolder(v);
    }
}


@Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
 }


public static class PersonViewHolder extends RecyclerView.ViewHolder {

    PersonViewHolder(View itemView) {
        super(itemView);

    }
}
}
person hassan karimi    schedule 16.12.2016
comment
Хотя этот фрагмент кода может решить вопрос, включение объяснения действительно помогает улучшить качество вашего поста. Помните, что вы отвечаете на вопрос для будущих читателей, и эти люди могут не знать причин вашего предложения кода. Также старайтесь не перегружать свой код пояснительными комментариями, это снижает читабельность как кода, так и пояснений! - person kayess; 16.12.2016