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】:我在一个有RecyclerView
和SnapHelper
的项目上使用它,不确定它是否是你想要的。
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 无法显示第一个/最后一个项目