SnapHelper 项目位置

Posted

技术标签:

【中文标题】SnapHelper 项目位置【英文标题】:SnapHelper Item Position 【发布时间】:2017-08-10 05:28:01 【问题描述】:

我使用垂直RecyclerView 列出我的项目并使用SnapHelper 捕捉中心项目。这个想法是随机选择,所以用户滑动屏幕或摇动设备,它就会滚动到随机位置。 项目数是 20,但是我使用 Integer.MAX_VALUE 作为 RecyclerView 中的元素数,并使用位置 Integer.MAX_VALUE / 2 初始化 RecyclerView 以创建某种无限列表。 要滚动到设备抖动的随机位置,我需要知道当前捕捉的项目位置。 有什么办法吗?

这是我的片段代码:

公共类 PlaceListFragment 扩展片段

private static final String TAG = "PlaceListFragment";
public static final String ARG_KEY1 = "key1";
private ArrayList<PlaceItem> places;

private RecyclerView recyclerView;

private SensorManager sensorManager;
private float accelValue;
private float accelLast;
private float shake;

SnapHelper snapHelper;

Vibrator vibe;


    public static PlaceListFragment newInstance() 

        Bundle args = new Bundle();

        PlaceListFragment fragment = new PlaceListFragment();
        fragment.setArguments(args);
        return fragment;
    

    public static PlaceListFragment newInstance(ArrayList<PlaceItem> places) 

        Bundle args = new Bundle();
        args.putParcelableArrayList(PlaceListActivity.KEY_PLACES, places);
        PlaceListFragment fragment = new PlaceListFragment();
        fragment.setArguments(args);
        return fragment;
    

    @Override
    public void onCreate(Bundle savedInstanceState) 
        Log.d(TAG, "onCreate()");
        super.onCreate(savedInstanceState);
        places = getArguments().getParcelableArrayList(PlaceListActivity.KEY_PLACES);

        accelValue = SensorManager.GRAVITY_EARTH;
        accelLast = SensorManager.GRAVITY_EARTH;
        shake = 0.00f;
        vibe = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE);
    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
        View v = inflater.inflate(R.layout.fragment_place_list, container, false);

        recyclerView = (RecyclerView) v.findViewById(R.id.place_list);

        snapHelper = new LinearSnapHelper();
        snapHelper.attachToRecyclerView(recyclerView);
        recyclerView.setOnFlingListener(snapHelper);

        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        recyclerView.setAdapter(new PlaceListAdapter(getActivity(), places));
        recyclerView.scrollToPosition(PlaceListAdapter.MIDDLE);

        sensorManager = (SensorManager) getActivity().getSystemService(Context.SENSOR_SERVICE);
        sensorManager.registerListener(sensorListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_NORMAL);

        return v;
    


    @Override
    public void onResume() 
        super.onResume();
    

    @Override
    public void onPause() 
        super.onPause();
    

    private final SensorEventListener sensorListener = new SensorEventListener() 
        @Override
        public void onSensorChanged(SensorEvent event) 

            float x = event.values[0];
            float y = event.values[1];
            float z = event.values[2];

            accelLast = accelValue;
            accelValue = (float) Math.sqrt((double) (x*x + y*y + z*z));
            float delta = accelValue - accelLast;
            shake = shake * 0.9f + delta;

            if (shake > 12) 
                vibe.vibrate(200);

            

        

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) 

        
    ;


这是适配器:

public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.PlaceAdapterHolder> 
    private final FragmentActivity context;
    public static final int HALF_MAX_VALUE = Integer.MAX_VALUE/2;
    public static int MIDDLE;
    private List<PlaceItem> placeItems;

    public static class PlaceAdapterHolder extends RecyclerView.ViewHolder 
        private ImageView image;
        private TextView textMain;
        private TextView textRating;


        public PlaceAdapterHolder(View itemView) 
            super(itemView);
            image = (ImageView) itemView.findViewById(R.id.icon);
            textMain = (TextView) itemView.findViewById(R.id.txt_main_line);
            textRating = (TextView) itemView.findViewById(R.id.txt_right_field);
        

        public void bindPlace(PlaceItem placeItem) 
            String placeName = placeItem.getName() == null? "?":placeItem.getName();
            String firstLetter = placeName.substring(0, 1);
            ColorGenerator generator = ColorGenerator.MATERIAL; // or use DEFAULT
            int color = generator.getColor(placeName);
            TextDrawable drawable = TextDrawable.builder()
                    .beginConfig()
                    .toUpperCase()
                    .endConfig()
                    .buildRect(firstLetter, color);
            image.setImageDrawable(drawable);
            textMain.setText(placeItem.getName());
            textRating.setText(placeItem.getRating());
        
    

    public PlaceListAdapter(FragmentActivity context, List<PlaceItem> placeItems) 
        this.context = context;
        this.placeItems = placeItems;
        MIDDLE = HALF_MAX_VALUE - HALF_MAX_VALUE % placeItems.size();
    

    @Override
    public PlaceListAdapter.PlaceAdapterHolder onCreateViewHolder(ViewGroup parent, int viewType) 
        final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.place_list_one_line_item, parent, false);
        return new PlaceAdapterHolder(view);
    

    @Override
    public int getItemCount() 
        return Integer.MAX_VALUE;
    

    @Override
    public void onBindViewHolder(PlaceListAdapter.PlaceAdapterHolder holder, final int position) 
        final PlaceItem placeItem = getItem(position);
        holder.bindPlace(placeItem);
        holder.itemView.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                FragmentManager fm = context.getSupportFragmentManager();
                PlaceDetailsFragment dialog = PlaceDetailsFragment.newInstance(getItem(position));
                dialog.show(fm, "DETAILS_DIALOG");
            
        );
    

    private PlaceItem getItem(int position)
    
        return placeItems.get(position % placeItems.size());
    

【问题讨论】:

【参考方案1】:

我在一个有RecyclerViewSnapHelper 的项目上使用它,不确定它是否是你想要的。

mRecyclerView.setHasFixedSize(true);

    // use a linear layout manager
    mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
    mRecyclerView.setLayoutManager(mLayoutManager);

    // specify an adapter (see also next example)
    mAdapter = new DemoSlidesAdapter(getApplicationContext());
    mRecyclerView.setAdapter(mAdapter);

    final SnapHelper snapHelper = new LinearSnapHelper();
    snapHelper.attachToRecyclerView(mRecyclerView);

    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() 

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) 
            super.onScrollStateChanged(recyclerView, newState);
            if(newState == RecyclerView.SCROLL_STATE_IDLE) 
                View centerView = snapHelper.findSnapView(mLayoutManager);
                int pos = mLayoutManager.getPosition(centerView);
                Log.e("Snapped Item Position:",""+pos);
            
        
    );

【讨论】:

完美运行,谢谢!没想到:) 我的解决办法是用linearLayoutManager.findFirstCompletelyVisibleItemPosition();,linearLayoutManager.findLastCompletelyVisibleItemPosition(); 然后找个中间 完美!谢谢! 完美答案。我也在***.com/questions/48062571/… 寻找它【参考方案2】:

我尝试将此代码与 PagerSnapHelper 一起使用来模拟寻呼机行为,这很有用,但我发现了一些需要解决的极端情况,如果你从最后一页快速移动到第一页并继续交换直到看到边界然后IDLE 状态不会发生,您会丢失索引。为了解决这个问题,我从 IF 中移出位置并为这个极端情况添加了一个额外的条件。

 override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) 
             super.onScrollStateChanged(recyclerView, newState)
             val centerView = snapHelper.findSnapView(mLayoutManager)
             val pos = mLayoutManager.getPosition(centerView!!)
             if (newState == RecyclerView.SCROLL_STATE_IDLE || (pos == 0 && newState == RecyclerView.SCROLL_STATE_DRAGGING)) 
                 Log.d("BINDING", "positionView SCROLL_STATE_IDLE: $pos")
             
         

代码在 kotlin 中,希望对您有所帮助

【讨论】:

【参考方案3】:
private fun recyclerViewScrollListener() = object: RecyclerView.OnScrollListener() 
    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) 
        super.onScrollStateChanged(recyclerView, newState)
        if (newState == RecyclerView.SCROLL_STATE_IDLE) 
            // LinearLayoutManager
            val pos = layoutManager.findFirstCompletelyVisibleItemPosition()
            Log.e(TAG, "onScrollStateChanged: $pos")
        
    

【讨论】:

【参考方案4】:
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener()
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) 
                ....
            
        )

【讨论】:

您能否解释一下为什么如何这段代码 sn-p 提供了问题的答案?谢谢...

以上是关于SnapHelper 项目位置的主要内容,如果未能解决你的问题,请参考以下文章

RecyclerView SnapHelper 无法显示第一个/最后一个项目

SnapHelper源码深度解析

SnapHelper源码深度解析

关于RecyclerView

全面解析:SnapHelper用法、原理,含演示效果对比+实现代码

RecyclerView + SnapHelper实现炫酷ViewPager效果