我有一个项目,我使用水平回收视图,我想要一个元素居中。我的实现有效,但不是在每种情况下都在这里检查这个GIF:
正如您可能注意到的,如果我从左边来,它会正确滚动。如果我来自右边,它会过度滚动,我不知道如何停止或如何解决这个问题。
我在这里将代码条带化为此示例:
public class DemoActivity extends ActionBarActivity implements View.OnClickListener {
private static final int JUMP_TO_LEFT = MyAdapter.NON_VISIBLE_ITEMS + MyAdapter.VISIBLE_ITEMS - 1;
private static final int JUMP_TO_RIGHT = MyAdapter.NON_VISIBLE_ITEMS;
private LinearLayoutManager mLayoutManager;
private RecyclerView mRecycler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
findViewById(android.R.id.button1).setOnClickListener(this);
mRecycler = (RecyclerView)findViewById(R.id.recycler);
MyAdapter mAdapter = new MyAdapter();
mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
mRecycler.setLayoutManager(mLayoutManager);
mRecycler.setHasFixedSize(true);
mRecycler.scrollToPosition(MyAdapter.NON_VISIBLE_ITEMS);
mRecycler.setAdapter(mAdapter);
}
@Override
public void onClick(View v) {
int pos = mLayoutManager.findFirstVisibleItemPosition();
int outer = (MyAdapter.VISIBLE_ITEMS - 1) / 2;
if(pos + outer >= MyAdapter.ITEM_IN_CENTER) {
mRecycler.smoothScrollToPosition(JUMP_TO_RIGHT);
} else {
mRecycler.smoothScrollToPosition(JUMP_TO_LEFT);
}
}
}
这是我的适配器:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.Holder> implements View.OnClickListener {
public static final int VISIBLE_ITEMS = 7;
public static final int NON_VISIBLE_ITEMS = 150;
private static final int TOTAL_ITEMS = VISIBLE_ITEMS + NON_VISIBLE_ITEMS * 2;
public static final int ITEM_IN_CENTER = (int)Math.ceil(VISIBLE_ITEMS / 2f) + NON_VISIBLE_ITEMS;
private Calendar mCalendar;
public MyAdapter() {
mCalendar = GregorianCalendar.getInstance();
setHasStableIds(true);
}
private int getToday() {
return (int)TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis());
}
@Override
public int getItemCount() {
return TOTAL_ITEMS;
}
@Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
final TextView tv = new TextView(parent.getContext());
int width = parent.getWidth() / VISIBLE_ITEMS;
tv.setLayoutParams(new TableRow.LayoutParams(width, ViewGroup.LayoutParams.MATCH_PARENT, 1));
tv.setGravity(Gravity.CENTER);
tv.setBackgroundColor(Color.TRANSPARENT);
DisplayMetrics metrics = tv.getContext().getResources().getDisplayMetrics();
float padding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, metrics);
tv.setLineSpacing(padding, 1f);
tv.setPadding(0, (int)padding, 0, 0);
tv.setOnClickListener(this);
return new Holder(tv);
}
@Override
public void onBindViewHolder(Holder holder, int position) {
int today = getToday();
mCalendar.setTimeInMillis(System.currentTimeMillis());
mCalendar.set(Calendar.HOUR_OF_DAY, 12); // set to noon to avoid energy saver time problems
mCalendar.add(Calendar.DAY_OF_YEAR, position - ITEM_IN_CENTER + 1);
DateFormat format = new SimpleDateFormat("E\nd");
String label = format.format(mCalendar.getTime()).replace(".\n", "\n");
int day = (int)TimeUnit.MILLISECONDS.toDays(mCalendar.getTimeInMillis());
holder.update(day, today, label);
}
@Override
public long getItemId(int position) {
mCalendar.setTimeInMillis(System.currentTimeMillis());
mCalendar.set(Calendar.HOUR_OF_DAY, 12); // set to noon to avoid energy saver time problems
mCalendar.add(Calendar.DAY_OF_YEAR, position - ITEM_IN_CENTER + 1);
DateFormat format = new SimpleDateFormat("dMMyyyy");
return Long.parseLong(format.format(mCalendar.getTime()));
}
@Override
public void onClick(View v) {
String day = ((TextView)v).getText().toString().replace("\n", " ");
Toast.makeText(v.getContext(), "You clicked on " + day, Toast.LENGTH_SHORT).show();
}
public class Holder extends RecyclerView.ViewHolder {
private final Typeface font;
private Holder(TextView v) {
super(v);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
font = Typeface.create("sans-serif-light", Typeface.NORMAL);
} else {
font = null;
}
}
public void update(int day, int today, String label) {
TextView tv = (TextView)itemView;
tv.setText(label);
if(day == today) {
tv.setTextSize(18);
tv.setTypeface(null, Typeface.BOLD);
} else {
tv.setTextSize(16);
tv.setTypeface(font, Typeface.NORMAL);
}
tv.setBackgroundColor(0xff8dc380);
}
}
}
你看到了原因吗?为了使您更简单,我还将此代码放在GitHub上。 https://github.com/rekire/RecylcerViewBug
答案 0 :(得分:14)
我找到了一个令人惊讶的简单解决方法:
@Override
public void onClick(View v) {
int pos = mLayoutManager.findFirstVisibleItemPosition();
int outer = (MyAdapter.VISIBLE_ITEMS + 1) / 2;
int delta = pos + outer - ForecastAdapter.ITEM_IN_CENTER;
//Log.d("Scroll", "delta=" + delta);
View firstChild = mForecast.getChildAt(0);
if(firstChild != null) {
mForecast.smoothScrollBy(firstChild.getWidth() * -delta, 0);
}
}
在这里,我计算自己跳跃的宽度,这正是我想要的。
答案 1 :(得分:5)
如果LinearLayoutManager具有垂直方向,您可以创建自己的SmoothScroller并覆盖calculateDyToMakeVisible()方法,您可以在其中设置所需的视图位置。例如,要在smoothScroll()之后使目标视图始终出现在RecyclerView的顶部,请写下:
class CustomLinearSmoothScroller extends LinearSmoothScroller {
public CustomLinearSmoothScroller(Context context) {
super(context);
}
@Override
public int calculateDyToMakeVisible(View view, int snapPreference) {
final RecyclerView.LayoutManager layoutManager = getLayoutManager();
if (!layoutManager.canScrollVertically()) {
return 0;
}
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)view.getLayoutParams();
final int top = layoutManager.getDecoratedTop(view) - params.topMargin;
final int bottom = layoutManager.getDecoratedBottom(view) + params.bottomMargin;
final int viewHeight = bottom - top;
final int start = layoutManager.getPaddingTop();
final int end = start + viewHeight;
return calculateDtToFit(top, bottom, start, end, snapPreference);
}
“top”和“bottom” - 目标视图的范围
“start”和“end” - 在smoothScroll期间应放置视图的点
答案 2 :(得分:0)
要支持平滑滚动,您必须覆盖 smoothScrollToPosition(RecyclerView,State,int)并创建一个 RecyclerView.SmoothScroller。
RecyclerView.LayoutManager负责 用于创建实际的滚动动作。如果要提供自定义 平滑滚动逻辑,覆盖smoothScrollToPosition(RecyclerView, 在LayoutManager中使用State,int。
在您的情况下,使用smoothScrollBy可能是一种解决方法(不需要此覆盖)。
答案 3 :(得分:0)
这对我有用:
itemsView.smoothScrollBy(-recyclerView.computeHorizontalScrollOffset(), 0)