代码之家  ›  专栏  ›  技术社区  ›  ductran

滚动时获取RecycleView的中心可见项

  •  63
  • ductran  · 技术社区  · 9 年前

    这就是我想要的:

    enter image description here

    如上图所示,我想在 RecycleView ,然后在滚动时获取中心项(以及向左或向右移动)
    这是我画水平线的尝试 循环视图 :

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

    有没有办法知道哪个项目被移到了 循环视图 ? 我怎么能滚动 循环视图 向左或向右只一个位置?

    使现代化 :我尝试使用滚动侦听器来获取中间位置,但它不能作为一个方面。

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

    并得到结果:

    enter image description here

    我只想在蓝色上更改所选项目(将文本改为白色) Rect

    11 回复  |  直到 4 年前
        1
  •  59
  •   TranHieu    9 年前

    我做了这样的东西。我可以做你需要的事。 首先,这是我的算术工作 enter image description here

    这是我的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);
    }
    

    这就是我的结果: enter image description here

    看这个视频 link ,这是我的应用演示

        2
  •  12
  •   Paulo Henrique Nonaka    8 年前

    有时需要将整个示例代码块放在一起,因为我们可能会错过一些东西。这就是我所拥有的,因为我可能在某个地方犯了一些小错误,所以可以随时改正。是的,这个答案是@tranhieu答案的扩展。谢谢@tranhieu。

    主活动.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;
            }
        }
    }
    

    活动_主.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>
    

    项目.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>
    

    尺寸.xml

    <resources>
        <dimen name="item_dob_width">100dp</dimen>
    </resources>
    
        3
  •  9
  •   jujka    6 年前

    哦,孩子。我已经找了差不多一个星期的答案,然后找到了解决方案。风俗 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)
    

    就是这样。最简单、最完美的解决方案

        4
  •  5
  •   firegloves    8 年前

    我在这里使用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,因为代码的可读性很差。使用此技术,如果项目被回收,您还必须管理项目的重新绘制。

    如果您使用的是customview类,则可以直接将其宽度设置为这些类。

    例如,这是我的填充类

    /**
     * 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/1)

    这是我的适配器,不要看与RecyclerView不匹配的方法。适配器,请注意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库,但它不是必需的

    希望有帮助

        5
  •  3
  •   Dionis Beqiraj    6 年前

    使用SNAPHELPER-更平滑的解决方案

    这是另一个使用 SnapHelper(快照助手) 。从@TranHieu的回答开始:

    https://stackoverflow.com/a/34647005/3944251

    并在此处由@sector11压缩:

    https://stackoverflow.com/a/38411582/3944251

    我编写了以下代码,也是基于上述两个答案,但它更简单,使用SnapHelper提供了更平滑的解决方案,如 android支持库24.2.0 .

    这里有 主要活动 班其余与@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;
            }
        }
    }
    
        6
  •  3
  •   Viral Patel    4 年前

    正如另一个答案中提到的,没有直接的方法可以做到这一点。

    这可能就是你如何实现你在问题中描述的目标。

    1. 知道屏幕上可见的项目数量。
    2. 每次滚动视图时,以编程方式选择中间项。
    3. 保留一个部分透明的图像,作为循环视图中间项目的覆盖。(您需要根据回收器视图的宽度或屏幕的宽度以及您选择放置的覆盖图像的宽度来计算坐标。
    4. 每次滚动时,在回收器视图下方的文本视图中刷新所选值。

    图像覆盖必须以一种相互连接的方式放置,并作为一个单独的控件。

        7
  •  2
  •   veeyikpong    5 年前

    您可以使用 LinearSnapHelper

    连接到您的回收器查看

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

    然后,要获得中心视图,请使用 snapHelper.findSnapView(horizontalScrollView.layoutManager)?

        8
  •  1
  •   user3579059    8 年前

    对于此功能,请使用EcoGallery库: https://github.com/falnatsheh/EcoGallery

        9
  •  0
  •   ThinkDeep    7 年前

    起初,我需要类似的东西,而不是这个。但我能够根据我的需要调整@TranHieu解决方案,所以我投票支持了他的解决方案。

    我想创建一个全屏水平循环视图,在用户sroll将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;
            }
        }
    }
    
        10
  •  0
  •   Community CDub    7 年前

    在我的案例中,我使用了另一种方法。

    你可以在这里找到deatils: RecyclerView - How highlight central visible item during scroll 1

    在我看来,我的解决方案比其他人更容易。

        11
  •  0
  •   Verhelst    6 年前

    如果有人正在寻找一个更通用的实现,下面是我根据这个线程的答案编写的代码:

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