Подтвердить что ты не робот

Получить центр видимого элемента RecycleView при прокрутке

Это то, что я хочу:

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

Как изображение выше, я хочу нарисовать осевую линию на RecycleView, затем получить элемент центра при прокрутке (а также перемещение влево или вправо)
Вот моя попытка нарисовать горизонтальный RecycleView:

    HorizontalAdapter adapter = new HorizontalAdapter(data);
    LinearLayoutManager layoutManager
            = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
    recycleView.setLayoutManager(layoutManager);
    recycleView.setAdapter(adapter);

Есть ли способ узнать, какой элемент перемещен в центр RecycleView? И как я могу прокручивать RecycleView налево или вправо только на одну позицию?

Обновление. Я попытался использовать прослушиватель прокрутки, чтобы получить среднюю позицию, но он не работает как аспект.

  @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            int firstPos = layoutManager.findFirstVisibleItemPosition();
            int lastPos = layoutManager.findLastVisibleItemPosition();
            int middle = Math.abs(lastPos - firstPos) / 2 + firstPos;

            int selectedPos = -1;
            for (int i = 0; i < adapter.getItemCount(); i++) {
                if (i == middle) {
                    adapter.getItem(i).setSelected(true);
                    selectedPos = i;
                } else {
                    adapter.getItem(i).setSelected(false);
                }
            }

            adapter.notifyDataSetChanged();
        }

И получите результат:

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

Я хочу изменить элемент selecte (сделать текст белым цветом), когда он находится на синем Rect

4b9b3361

Ответ 1

Я сделал что-то подобное. Я могу сделать именно то, что вам нужно. Прежде всего, вот как работает мой алогритм введите описание изображения здесь

Это мой адаптер recyclerView

public class DateAdapter extends RecyclerView.Adapter<DateAdapter.DateViewHolder> {
private ArrayList<LabelerDate> dateDataList;


private static final int VIEW_TYPE_PADDING = 1;
private static final int VIEW_TYPE_ITEM = 2;
private int paddingWidthDate = 0;

private int selectedItem = -1;

public DateAdapter(ArrayList<LabelerDate> dateData, int paddingWidthDate) {
    this.dateDataList = dateData;
    this.paddingWidthDate = paddingWidthDate;

}


@Override
public DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (viewType == VIEW_TYPE_ITEM) {
        final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_date,
                parent, false);
        return new DateViewHolder(view);
    } else {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_padding,
                parent, false);

        RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
        layoutParams.width = paddingWidthDate;
        view.setLayoutParams(layoutParams);
        return new DateViewHolder(view);
    }
}

@Override
public void onBindViewHolder(DateViewHolder holder, int position) {
    LabelerDate labelerDate = dateDataList.get(position);
    if (getItemViewType(position) == VIEW_TYPE_ITEM) {
        if(labelerDate.dateType.equals(BirthDayActivity.DateType.C31))
                holder.tvDate.setText(String.valueOf(labelerDate.valueDate));
                holder.tvDate.setVisibility(View.VISIBLE);
                holder.imgSmall.setVisibility(View.VISIBLE);

        if (position == selectedItem) {
            holder.tvDate.setTextColor(Color.parseColor("#094673"));
            holder.tvDate.setTextSize(35);
            holder.imgSmall.setBackgroundResource(R.color.textviewbold);

        } else {
            holder.tvDate.setTextColor(Color.GRAY);
            holder.tvDate.setTextSize(35);
            holder.imgSmall.setBackgroundResource(R.color.gray);
        }
    }
}

public void setSelecteditem(int selecteditem) {
    this.selectedItem = selecteditem;
    notifyDataSetChanged();
}

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

@Override
public int getItemViewType(int position) {
    LabelerDate labelerDate = dateDataList.get(position);
    if (labelerDate.dateType.equals(BirthDayActivity.DateType.NONE)) {
        return VIEW_TYPE_PADDING;
    }
    return VIEW_TYPE_ITEM;
}


public class DateViewHolder extends RecyclerView.ViewHolder {
    public TextView tvDate;
    public ImageView imgSmall;

    public DateViewHolder(View itemView) {
        super(itemView);
        tvDate = (TextView) itemView.findViewById(R.id.tvNumberDate);
        imgSmall = (ImageView) itemView.findViewById(R.id.small_marked_dob);
    }
}}

Это самый важный алорифм:

public void getRecyclerviewDate() {
    recyclerViewDate = (RecyclerView) findViewById(R.id.recyclerViewDay);
    ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver();
    vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this);
            finalWidthDate = recyclerViewDate.getMeasuredWidth();
            itemWidthDate = getResources().getDimension(R.dimen.item_dob_width);
            paddingDate = (finalWidthDate - itemWidthDate) / 2;
            firstItemWidthDate = paddingDate ;
            allPixelsDate = 0;

            final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext());
            dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
            recyclerViewDate.setLayoutManager(dateLayoutManager);
            recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    synchronized (this) {
                         if(newState == RecyclerView.SCROLL_STATE_IDLE){           
                            calculatePositionAndScrollDate(recyclerView);
                        }
                    }

                }

                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    allPixelsDate += dx;
                }
            });
            if (labelerDates == null)
                labelerDates = new ArrayList<>();
            labelerDates.addAll(genLabelerDate(currentMonth, currentYear));
            dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate);
            recyclerViewDate.setAdapter(dateAdapter);
            return true;
        }
    });
}
/* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/

private void calculatePositionAndScrollDate(RecyclerView recyclerView) {
    int expectedPositionDate = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate);

    if (expectedPositionDate == -1) {
        expectedPositionDate = 0;
    } else if (expectedPositionDate >= recyclerView.getAdapter().getItemCount() - 2) {
        expectedPositionDate--;
    }
    scrollListToPositionDate(recyclerView, expectedPositionDate);

}
/* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/
private void scrollListToPositionDate(RecyclerView recyclerView, int expectedPositionDate) {
    float targetScrollPosDate = expectedPositionDate * itemWidthDate + firstItemWidthDate - paddingDate;
    float missingPxDate = targetScrollPosDate - allPixelsDate;
    if (missingPxDate != 0) {
        recyclerView.smoothScrollBy((int) missingPxDate, 0);
    }
}
private void setDateValue() {
    int expectedPositionDateColor = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate);
    setColorDate = expectedPositionDateColor + 1;
    //set color here
    dateAdapter.setSelecteditem(setColorDate);
}
 @Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);   
    allPixelsDate = savedInstanceState.getFloat(BUNDLE_LIST_PIXELS_DATE);
    allPixelsDateChanged = savedInstanceState.getFloat(BUNDLE_LIST_PIXELS_DATE_CHANGED);
}

@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putFloat(BUNDLE_LIST_PIXELS_DATE, allPixelsDate);
    outState.putFloat(BUNDLE_LIST_PIXELS_DATE_CHANGED, allPixelsDateChanged);
}

И это мой результат: введите описание изображения здесь

Посмотрите на это видео ссылка, это демонстрация моего приложения

Ответ 2

Иногда требуется весь блок кода примера вместе, потому что мы можем что-то пропустить. Вот что я имею, не стесняйтесь исправить что-либо, поскольку я могу совершить какую-то небольшую ошибку. И Да, этот ответ является продолжением ответа @tranhieu. Спасибо @tranhieu.

MainActivity.java

package com.test;

import android.app.Activity;
import android.graphics.Color;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.TextView;

import java.util.ArrayList;

public class MainActivity extends Activity {

    private static final String TAG = MainActivity.class.getSimpleName();

    public float firstItemWidthDate;
    public float paddingDate;
    public float itemWidthDate;
    public int allPixelsDate;
    public int finalWidthDate;
    private DateAdapter dateAdapter;
    private ArrayList<LabelerDate> labelerDates = new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getRecyclerviewDate();

    }


    public void getRecyclerviewDate() {
        final RecyclerView recyclerViewDate = (RecyclerView) findViewById(R.id.rv_tasks_date);
        if (recyclerViewDate != null) {
            recyclerViewDate.postDelayed(new Runnable() {
                @Override
                public void run() {
                    setDateValue();
                }
            }, 300);
            recyclerViewDate.postDelayed(new Runnable() {
                @Override
                public void run() {
                    recyclerViewDate.smoothScrollToPosition(dateAdapter.getItemCount()-1);
                    setDateValue();
                }
            }, 5000);
        }
        ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver();
        vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {


            @Override
            public boolean onPreDraw() {
                recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this);
                finalWidthDate = recyclerViewDate.getMeasuredWidth();
                itemWidthDate = getResources().getDimension(R.dimen.item_dob_width);
                paddingDate = (finalWidthDate - itemWidthDate) / 2;
                firstItemWidthDate = paddingDate;
                allPixelsDate = 0;

                final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext());
                dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
                recyclerViewDate.setLayoutManager(dateLayoutManager);
                recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() {
                    @Override
                    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                        super.onScrollStateChanged(recyclerView, newState);
                        synchronized (this) {
                            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                                calculatePositionAndScrollDate(recyclerView);
                            }
                        }

                    }

                    @Override
                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                        super.onScrolled(recyclerView, dx, dy);
                        allPixelsDate += dx;
                    }
                });
                if (labelerDates == null) {
                    labelerDates = new ArrayList<>();
                }
                genLabelerDate();
                dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate);
                recyclerViewDate.setAdapter(dateAdapter);
                dateAdapter.setSelecteditem(dateAdapter.getItemCount() - 1);
                return true;
            }
        });
    }

    private void genLabelerDate() {
        for (int i = 0; i < 32; i++) {
            LabelerDate labelerDate = new LabelerDate();
            labelerDate.setNumber(Integer.toString(i));
            labelerDates.add(labelerDate);

            if (i == 0 || i == 31) {
                labelerDate.setType(DateAdapter.VIEW_TYPE_PADDING);
            } else {
                labelerDate.setType(DateAdapter.VIEW_TYPE_ITEM);
            }
        }
    }
/* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/

    private void calculatePositionAndScrollDate(RecyclerView recyclerView) {
        int expectedPositionDate = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate);

        if (expectedPositionDate == -1) {
            expectedPositionDate = 0;
        } else if (expectedPositionDate >= recyclerView.getAdapter().getItemCount() - 2) {
            expectedPositionDate--;
        }
        scrollListToPositionDate(recyclerView, expectedPositionDate);

    }

    /* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/
    private void scrollListToPositionDate(RecyclerView recyclerView, int expectedPositionDate) {
        float targetScrollPosDate = expectedPositionDate * itemWidthDate + firstItemWidthDate - paddingDate;
        float missingPxDate = targetScrollPosDate - allPixelsDate;
        if (missingPxDate != 0) {
            recyclerView.smoothScrollBy((int) missingPxDate, 0);
        }
        setDateValue();
    }

    //
    private void setDateValue() {
        int expectedPositionDateColor = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate);
        int setColorDate = expectedPositionDateColor + 1;
//        set color here
        dateAdapter.setSelecteditem(setColorDate);
    }


    public class DateAdapter extends RecyclerView.Adapter<DateAdapter.DateViewHolder> {
        private ArrayList<LabelerDate> dateDataList;


        private static final int VIEW_TYPE_PADDING = 1;
        private static final int VIEW_TYPE_ITEM = 2;
        private int paddingWidthDate = 0;

        private int selectedItem = -1;

        public DateAdapter(ArrayList<LabelerDate> dateData, int paddingWidthDate) {
            this.dateDataList = dateData;
            this.paddingWidthDate = paddingWidthDate;

        }


        @Override
        public DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == VIEW_TYPE_ITEM) {
                final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,
                    parent, false);
                return new DateViewHolder(view);
            } else {
                View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,
                    parent, false);

                RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
                layoutParams.width = paddingWidthDate;
                view.setLayoutParams(layoutParams);
                return new DateViewHolder(view);
            }
        }

        @Override
        public void onBindViewHolder(DateViewHolder holder, int position) {
            LabelerDate labelerDate = dateDataList.get(position);
            if (getItemViewType(position) == VIEW_TYPE_ITEM) {
                holder.tvDate.setText(labelerDate.getNumber());
                holder.tvDate.setVisibility(View.VISIBLE);

                Log.d(TAG, "default " + position + ", selected " + selectedItem);
                if (position == selectedItem) {
                    Log.d(TAG, "center" + position);
                    holder.tvDate.setTextColor(Color.parseColor("#76FF03"));
                    holder.tvDate.setTextSize(35);

                } else {
                    holder.tvDate.setTextColor(Color.WHITE);
                    holder.tvDate.setTextSize(18);
                }
            } else {
                holder.tvDate.setVisibility(View.INVISIBLE);
            }
        }

        public void setSelecteditem(int selecteditem) {
            this.selectedItem = selecteditem;
            notifyDataSetChanged();
        }

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

        @Override
        public int getItemViewType(int position) {
            LabelerDate labelerDate = dateDataList.get(position);
            if (labelerDate.getType() == VIEW_TYPE_PADDING) {
                return VIEW_TYPE_PADDING;
            } else {
                return VIEW_TYPE_ITEM;
            }

        }


        public class DateViewHolder extends RecyclerView.ViewHolder {
            public TextView tvDate;

            public DateViewHolder(View itemView) {
                super(itemView);
                tvDate = (TextView) itemView.findViewById(R.id.txt_date);
            }
        }
    }

    private class LabelerDate {
        private int type;
        private String number;

        public String getNumber() {
            return number;
        }

        public void setNumber(String number) {
            this.number = number;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }
    }
}

activity_main.xml

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

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

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_tasks_date"
            android:layout_width="match_parent"
            android:layout_height="48dp" />

        <ImageView
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="center"
            android:layout_marginTop="48dp"
            android:src="@android:drawable/ic_dialog_info" />
    </FrameLayout>

</LinearLayout>

item.xml

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

    <TextView
        android:id="@+id/txt_date"
        android:layout_width="@dimen/item_dob_width"
        android:layout_height="48dp"
        android:text="32"
        android:textColor="@android:color/white"
        android:background="@android:color/darker_gray"
        android:textSize="28sp"
        android:gravity="center"/>

</LinearLayout>

dimens.xml

<resources>
    <dimen name="item_dob_width">100dp</dimen>
</resources>

Ответ 3

Я использую SnapHelper прямо здесь:

    // init snaphelper        
    SnapHelper snapHelper = new LinearSnapHelper();
    snapHelper.attachToRecyclerView(recyclerView)

    // init layout manager
    LinearLayoutManager layoutManager = new LinearLayoutManager(mainActivity);
    layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
    recyclerView.setLayoutManager(layoutManager);

    // init adapter
    adatper.setSnapHelper(snapHelper);
    adatper.setLayoutManager(layoutManager);

    adatper.initAdapter(new Float((DisplayHelper.getDisplayWidth(mainActivity) / 2) - (fooViewWidth / 2)).intValue());
    recyclerView.setAdapter(adatper);

Как сказал TranHieu, решение вставки 2-х элементов для заполнения (в начале и в конечных положениях) является хорошим.

Мне не нравится использование ViewTreeObserver из-за плохой читаемости кода. С помощью этого метода вы также должны управлять перерисованием элементов, если они переработаны.

Если вы используете классы пользовательского вида, вы можете установить его ширину непосредственно в эти классы.

Например, это мой класс заполнения

/**
 * Created by firegloves on 25/09/15.
 */
@EViewGroup(R.layout.view_padding)
public class PaddingView extends FooView {

    Context mCtx;

    public PaddingView(Context context) {
        super(context);
        mCtx = context;
    }


    public void setWidth(int width) {
        setLayoutParams(new LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
    }

}

В моем адаптере я сохраняю нужную ширину элемента заполнения, равную (displayWidth/2) - (realItemWidth/2)

Это мой адаптер, не смотрите на методы, не соответствующие RecyclerView.Adapter, обратите внимание на метод initAdapter и метод onCreateItemView

@EBean
public class FooAdapterRecycler extends RecyclerViewAdapterBase<Foo, FooView> {

    private final int TYPE_PADDING_VIEW = 0;
    private final int TYPE_REAL_VIEW = 1;

    @RootContext
    Context ctx;
    @Bean(Finder.class)
    IFinder finder;

    SnapHelper snapHelper;
    RecyclerView.LayoutManager layoutManager;

    private int paddingWidth = 0;

    /**
     * preleva i dati dal finder
     */
    public void initAdapter(int paddingWidth) {

        /*******************************
         * THIS CODE IS THE IMPORTANT ONE
         ******************************/

        this.paddingWidth = paddingWidth;

        // add 1 item for initial space
        mItems = new ArrayList<>();
        Foo foo = new Foo();
        mItems.add(foo);

        // get real items from finder
        mItems.addAll(finder.findAll());

        // add 1 item for final space
        mItems = new ArrayList<>();
        Foo foo2 = new Foo();
        mItems.add(foo2);

    }


    @Override
    public int getItemViewType(int position) {
        if (position == 0 || position == getItemCount()-1) {
            return TYPE_PADDING_VIEW;
        } else {
            return TYPE_REAL_VIEW;
        }
    }

    @Override
    protected FooView onCreateItemView(ViewGroup parent, int viewType) {

        /*******************************
         * THIS CODE IS THE IMPORTANT ONE
         ******************************/

        if (viewType == TYPE_PADDING_VIEW) {
            PaddingView view = PaddingView_.build(ctx);
            view.setWidth(paddingWidth);
            return view;
        } else {
            return FooView_.build(ctx);
        }
    }

    public void setSnapHelper(SnapHelper snapHelper) {
        this.snapHelper = snapHelper;
    }

    public void setLayoutManager(RecyclerView.LayoutManager layoutManager) {
        this.layoutManager = layoutManager;
    }
}

Я использую библиотеку AndroidAnnotations, но это не требуется

Надеюсь, что поможет

Ответ 4

Как уже упоминалось в другом ответе, нет прямого способа сделать это.

Вероятно, вы можете достичь того, что вы описали в вопросе.

  • Знайте количество элементов, видимых на экране.
  • Выберите средний элемент программно каждый раз, когда просматривается представление.
  • Сохраняйте частично прозрачное изображение как оверлей на среднем элементе в recyclerview. (Вам нужно будет вычислить координаты в зависимости от ширины вида ресайклера или ширины экрана и ширины наложенного изображения, которое вы выберете.
  • Обновите выбранное значение в текстовом представлении под просмотром ресайлера каждый раз, когда есть прокрутка.

Наложения изображений должны быть помещены таким образом, чтобы они отображались как один элемент управления.

Ответ 5

О, парень. Я искал этот ответ почти неделю, а затем нашел решение. Пользовательский LayoutManagers? Нет. ItemDecorator? Нет.

Вот самый простой способ сделать это:

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:paddingStart="150dp"
    android:paddingEnd="150dp"
    android:clipToPadding="false" />

Критическая часть:

    android:paddingStart="150dp"
    android:paddingEnd="150dp"
    android:clipToPadding="false"

А затем просто назначьте SnapHelper своему RecylcerView:

val snapHelper = LinearSnapHelper()
snapHelper.attachToRecyclerView(recyclerView)

Это оно. Самое простое и идеальное решение проблемы

Ответ 6

ИСПОЛЬЗОВАНИЕ SNAPHELPER - ГЛАВНОЕ РЕШЕНИЕ

Вот еще одно решение, использующее SnapHelper. Начиная с ответа @TranHieu здесь:

fooobar.com/questions/161445/...

и сжатый @сектора11 здесь:

fooobar.com/questions/161445/...

Я написал следующий код, который также основан на обоих ответах выше, но он проще и предлагает более плавное решение с использованием SnapHelper, представленного в библиотеке поддержки Android 24.2.0.

Здесь у вас есть класс MainActivity. Остальное то же самое с ответом @sector11.

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.LinearSnapHelper;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.TextView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();

    public float firstItemWidthDate;
    public float itemWidthDate;
    public int allPixelsDate;
    public int finalWidthDate;
    private DateAdapter dateAdapter;
    private ArrayList<LabelerDate> labelerDates;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        labelerDates = new ArrayList<>();
        getRecyclerviewDate();

    }


    public void getRecyclerviewDate() {
        final RecyclerView recyclerViewDate = (RecyclerView) findViewById(R.id.rv_tasks_date);
        recyclerViewDate.postDelayed(new Runnable() {
            @Override
            public void run() {
                //recyclerViewDate.smoothScrollToPosition(dateAdapter.getItemCount()-1);
                setDateValue();
            }
        }, 300);
        ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver();
        vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

            @Override
            public boolean onPreDraw() {
                recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this);
                finalWidthDate = recyclerViewDate.getMeasuredWidth();
                itemWidthDate = getResources().getDimension(R.dimen.item_dob_width);
                firstItemWidthDate = (finalWidthDate - itemWidthDate) / 2;
                allPixelsDate = 0;

                final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext());
                dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
                recyclerViewDate.setLayoutManager(dateLayoutManager);

                /* Create a LinearSnapHelper and attach the recyclerView to it. */
                final LinearSnapHelper snapHelper = new LinearSnapHelper();
                snapHelper.attachToRecyclerView(recyclerViewDate);

                recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() {
                    @Override
                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                        allPixelsDate += dx;
                        recyclerView.post(new Runnable() {
                            public void run() {
                                setDateValue();
                            }
                        });
                    }
                });

                genLabelerDate();
                dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate);
                recyclerViewDate.setAdapter(dateAdapter);
                dateAdapter.setSelecteditem(dateAdapter.getItemCount() - 1);
                return true;
            }
        });
    }

    private void genLabelerDate() {
        for (int i = 0; i < 32; i++) {
            LabelerDate labelerDate = new LabelerDate();
            labelerDate.setNumber(Integer.toString(i));
            labelerDates.add(labelerDate);

            if (i == 0 || i == 31) {
                labelerDate.setType(DateAdapter.VIEW_TYPE_PADDING);
            } else {
                labelerDate.setType(DateAdapter.VIEW_TYPE_ITEM);
            }
        }
    }

    //
    private void setDateValue() {
        int expectedPositionDateColor = Math.round(allPixelsDate / itemWidthDate);
        int setColorDate = expectedPositionDateColor + 1;
//        set color here
        dateAdapter.setSelecteditem(setColorDate);
    }


    public class DateAdapter extends RecyclerView.Adapter<DateAdapter.DateViewHolder> {
        private ArrayList<LabelerDate> dateDataList;


        private static final int VIEW_TYPE_PADDING = 1;
        private static final int VIEW_TYPE_ITEM = 2;
        private int paddingWidthDate = 0;

        private int selectedItem = -1;

        public DateAdapter(ArrayList<LabelerDate> dateData, int paddingWidthDate) {
            this.dateDataList = dateData;
            this.paddingWidthDate = paddingWidthDate;

        }


        @Override
        public DateAdapter.DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
            if (viewType == VIEW_TYPE_PADDING) {
                RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
                layoutParams.width = paddingWidthDate;
                view.setLayoutParams(layoutParams);
            }
            return new DateViewHolder(view);
        }

        @Override
        public void onBindViewHolder(DateAdapter.DateViewHolder holder, int position) {
            LabelerDate labelerDate = dateDataList.get(position);
            if (getItemViewType(position) == VIEW_TYPE_ITEM) {
                holder.tvDate.setText(labelerDate.getNumber());
                holder.tvDate.setVisibility(View.VISIBLE);

                Log.d(TAG, "default " + position + ", selected " + selectedItem);
                if (position == selectedItem) {
                    Log.d(TAG, "center" + position);
                    holder.tvDate.setTextColor(Color.parseColor("#76FF03"));
                    holder.tvDate.setTextSize(35);

                } else {
                    holder.tvDate.setTextColor(Color.WHITE);
                    holder.tvDate.setTextSize(18);
                }
            } else {
                holder.tvDate.setVisibility(View.INVISIBLE);
            }
        }

        public void setSelecteditem(int selecteditem) {
            this.selectedItem = selecteditem;
            notifyDataSetChanged();
        }

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

        @Override
        public int getItemViewType(int position) {
            LabelerDate labelerDate = dateDataList.get(position);
            if (labelerDate.getType() == VIEW_TYPE_PADDING) {
                return VIEW_TYPE_PADDING;
            } else {
                return VIEW_TYPE_ITEM;
            }

        }


        public class DateViewHolder extends RecyclerView.ViewHolder {
            public TextView tvDate;

            public DateViewHolder(View itemView) {
                super(itemView);
                tvDate = (TextView) itemView.findViewById(R.id.txt_date);
            }
        }
    }

    private class LabelerDate {
        private int type;
        private String number;

        public String getNumber() {
            return number;
        }

        public void setNumber(String number) {
            this.number = number;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }
    }
}

Ответ 8

Я не думаю, что есть какой-либо прямой подход для достижения этого. Вы можете попробовать это -

listView.setOnScrollListener(слушатель);

@Override

public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {
    int firstVisibleRow = listView.getFirstVisiblePosition();
    int lastVisibleRow = listView.getLastVisiblePosition();
    int count - ((int*)count/2;
    int middle = listview.getChildAt(count - ((int)count/2));
    }
}

вы также можете ссылаться на этот ответ fooobar.com/questions/161449/... fooobar.com/questions/161454/...

Ответ 9

Сначала мне нужно было что-то похожее, а не это. Но я смог адаптировать решение @TranHieu к моим потребностям, поэтому я проголосовал за его решение.

Я хотел создать полноэкранный горизонтальный recyclerview, который после обновления прокрутки пользователя scrollPosition до mostVisibleItem.

Настройка:

private void setUpScrolling() {
    mRecyclerVIew.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            mRecyclerVIew.getViewTreeObserver().removeOnPreDrawListener(this);
            CustomScrollListener listener = (CustomScrollListener) mScrollListener;
            listener.width = mRecyclerVIew.getMeasuredWidth();
            listener.dx = 0;
            return true;
        }
    });
}

Слушатель:

private class CustomScrollListener extends OnScrollListener {
    private int mLastDx = 0;
    int width = 0;
    int dx = 0;

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
            if (mLastDx != dx) {
                scrollToMostVisibleItem();
            } else {
                dx = 0;
                mLastDx = 0;
            }
        }
        super.onScrollStateChanged(recyclerView, newState);
    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        this.dx += dx;
    }

    private void scrollToMostVisibleItem() {
        int direction = (dx > 0) ? 1 : -1;
        dx = Math.abs(dx);
        int shiftCount = Math.round(dx / width);
        int pixelShift = dx % width;
        if (pixelShift > width / 2) {
            shiftCount++;
        }

        float targetScrollPixels = shiftCount * width;
        float finalScrollPixels = (targetScrollPixels - dx) * direction;
        if (finalScrollPixels != 0) {
            mRecyclerVIew.smoothScrollBy((int) finalScrollPixels, 0);
            mLastDx = (int) finalScrollPixels;
            dx = 0;
        }
    }
}

Ответ 11

Если кто-то ищет более общую реализацию, вот мой код, основанный на ответах этой темы:

Добавьте CenterLinearSnapHelper

public class CenterLinearSnapHelper extends LinearSnapHelper {

    //Constants
    public static final String TAG = CenterLinearSnapHelper.class.getSimpleName();

    //Attributes
    private Context context;
    private float itemWidth;
    private OnPaddingComputationListener listener;

    //Constructors

    /**
     * A linear snap helper which helps centering the items in a recyclerview.
     *
     * @param itemWidth The (fixed) width of a child view in pixels.
     */
    public CenterLinearSnapHelper(float itemWidth) {
        this.itemWidth = itemWidth;
    }

    public void attachToRecyclerView(@Nullable RecyclerView recyclerView,
                                     @NonNull OnPaddingComputationListener listener) throws IllegalStateException {
        this.listener = listener;

        //Calculates the padding for the first and end item
        calculatePadding(recyclerView);

        //Create a LinearSnapHelper and attach the recyclerView to it.
        attachToRecyclerView(recyclerView);
    }

    public float getItemWidth() {
        return itemWidth;
    }

    private void calculatePadding(RecyclerView recyclerView) {
        if (recyclerView == null)
            return;

        ViewTreeObserver observer = recyclerView.getViewTreeObserver();
        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

            @Override
            public boolean onPreDraw() {
                recyclerView.getViewTreeObserver().removeOnPreDrawListener(this);
                int finalWidth = recyclerView.getMeasuredWidth();
                float padding = (finalWidth - itemWidth) / 2;
                listener.onPadding(padding, finalWidth);
                return true;
            }
        });
    }

    public interface OnPaddingComputationListener {
        void onPadding(float padding, int finalWidth);
    }

}

В своей деятельности/фрагменте, где вы создаете свой RecyclerView:

float itemWidth = getResources().getDimension(R.dimen.favorite_room_width);
CenterLinearSnapHelper snapHelper = new CenterLinearSnapHelper(itemWidth);
snapHelper.attachToRecyclerView(binding.listFavorites, (padding, finalWidth) -> {
    //Set the adapter
    roomAdapter = new RoomAdapter(requireContext(), rooms);
    roomAdapter.addPaddingItems((int) padding);
    roomAdapter.setOnToggleClickListener(FavoritesFragment.this);
    binding.listFavorites.setAdapter(roomAdapter);
});

В вашем адаптере:

public void addPaddingItems(int padding) {
    if (padding < 0)
        throw new IllegalStateException("Padding cannot be smaller than 0");

    this.padding = padding;
    //Add 2 new items as the first and last
    //NOTE: If you update your existing dataset (e.g add new items), you should redo the calculation!
    rooms.add(0, new Room("First"));
    rooms.add(rooms.size(), new Room("Last"));
}


@Override
public int getItemViewType(int position) {
    if (padding >= 0 && (position == 0 || position == rooms.size() - 1)) {
        return VIEW_TYPE_PADDING;
    }

    return VIEW_TYPE_ITEM;
}

@NonNull
@Override
public RoomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    ViewFavoriteRoomBinding binding = DataBindingUtil.inflate(inflater, R.layout.view_favorite_room, parent, false);

    if (viewType == VIEW_TYPE_PADDING) {
        RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) binding.getRoot().getLayoutParams();
        layoutParams.width = padding;
        binding.getRoot().setLayoutParams(layoutParams);
    }

    RoomViewHolder viewHolder = new RoomViewHolder(context, binding, onToggleClickListener);
    viewHolder.getRecyclerView().setRecycledViewPool(viewPool);
    return viewHolder;
}