Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android RecyclerView未按预期滚动_Android_Android Animation_Smooth Scrolling_Android Recyclerview - Fatal编程技术网

Android RecyclerView未按预期滚动

Android RecyclerView未按预期滚动,android,android-animation,smooth-scrolling,android-recyclerview,Android,Android Animation,Smooth Scrolling,Android Recyclerview,我有一个项目,我使用一个水平的回收视图,我想中心一个元素。我的实现工作正常,但并非在所有情况下都可以在此处检查此GIF: 你可能会注意到,如果我从左边来,它会正确地滚动。如果我是右翼的话,我会犯很多错误,我不知道如何停止,也不知道如何解决 我将代码分条到以下示例: public class DemoActivity extends ActionBarActivity implements View.OnClickListener { private static final int J

我有一个项目,我使用一个水平的回收视图,我想中心一个元素。我的实现工作正常,但并非在所有情况下都可以在此处检查此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);
        }
    }
}
公共类MyAdapter扩展了RecyclerView。适配器实现了View.OnClickListener{
公共静态最终整数可见项=7;
公共静态最终整数不可见项=150;
私有静态最终整数合计项目=可见项目+不可见项目*2;
公共静态final int ITEM_IN_CENTER=(int)Math.ceil(VISIBLE_ITEMS/2f)+非VISIBLE_ITEMS;
私人日历;
公共MyAdapter(){
mCalendar=GregorianCalendar.getInstance();
setHasStableIds(true);
}
private int getToday(){
return(int)TimeUnit.millises.toDays(System.currentTimeMillis());
}
@凌驾
public int getItemCount(){
返回总项目;
}
@凌驾
public Holder onCreateViewHolder(视图组父级,int-viewType){
final TextView tv=新的TextView(parent.getContext());
int width=parent.getWidth()/VISIBLE\u ITEMS;
tv.setLayoutParams(新的TableRow.LayoutParams(宽度,ViewGroup.LayoutParams.MATCH_父项,1));
电视。设置重力(重力。重心);
tv.setBackgroundColor(彩色透明);
DisplayMetrics=tv.getContext().getResources().getDisplayMetrics();
浮动填充=TypedValue.applyDimension(TypedValue.COMPLEX\u UNIT\u DIP,10,度量);
tv.设置行距(填充,1f);
设置填充(0,(int)填充,0,0);
tv.setOnClickListener(此);
归还新的支架(电视);
}
@凌驾
公共无效onBindViewHolder(Holder Holder,内部位置){
int today=getToday();
mCalendar.setTimeInMillis(System.currentTimeMillis());
mCalendar.set(Calendar.HOUR OF_DAY,12);//设置为中午,以避免节能时间问题
mCalendar.add(Calendar.DAY\u OF\u YEAR,position-ITEM\u IN\u CENTER+1);
DateFormat格式=新的SimpleDataFormat(“E\nd”);
String label=format.format(mCalendar.getTime()).replace(“.\n”和“\n”);
int day=(int)TimeUnit.millises.toDays(mCalendar.getTimeInMillis());
持有者。更新(日期、今天、标签);
}
@凌驾
公共长getItemId(int位置){
mCalendar.setTimeInMillis(System.currentTimeMillis());
mCalendar.set(Calendar.HOUR OF_DAY,12);//设置为中午,以避免节能时间问题
mCalendar.add(Calendar.DAY\u OF\u YEAR,position-ITEM\u IN\u CENTER+1);
DateFormat格式=新的SimpleDataFormat(“dMMyyyy”);
返回Long.parseLong(format.format(mCalendar.getTime());
}
@凌驾
公共void onClick(视图v){
字符串day=((TextView)v.getText().toString().replace(“\n”,”);
Toast.makeText(v.getContext(),“您点击了”+day,Toast.LENGTH\u SHORT.show();
}
公共类持有者扩展了RecyclerView.ViewHolder{
专用最终字体;
私人持有人(TextView v){
超级(五);
if(Build.VERSION.SDK\u INT>=Build.VERSION\u代码.冰淇淋\u三明治){
字体=字体。创建(“无衬线光”,字体。普通);
}否则{
font=null;
}
}
公共无效更新(整数日、整数日、字符串标签){
TextView tv=(TextView)项目视图;
tv.setText(标签);
如果(天==今天){
电视节目(18),;
tv.setTypeface(null,Typeface.BOLD);
}否则{
电视节目(16),;
设置字体(字体、字体、普通);
}
电视背景色(0xff8dc380);
}
}
}

你觉得有什么原因吗?为了让您更简单,我还将此代码放在GitHub上

我发现了一个令人惊讶的简单解决方法:

@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);
    }
}
这里我自己计算跳跃的宽度,这正是我想要的

要支持平滑滚动,必须覆盖 smoothScrollToPosition(RecyclerView、State、int)并创建 RecyclerView.SmoothScroller

RecyclerView.LayoutManager负责 用于创建实际的滚动动作。如果您想提供自定义 平滑滚动逻辑,覆盖平滑滚动位置(RecyclerView, 在LayoutManager中声明,int)


在您的情况下,使用smoothScrollBy可能是一种解决方法(不需要此替代)。

在使用垂直方向的LinearLayoutManager的情况下,您可以创建自己的SmoothScroller并替代CalculatedyToMakeMakeVisible()方法,从中可以设置所需的视图位置。例如,要使目标视图在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);
    }
“顶部”和“底部”-目标视图的边界

“开始”和“结束”-在smoothScroll过程中视图应该放置在这两个点之间

这对我很有用:

itemsView.smoothScrollBy(-recyclerView.computeHorizontalScrollOffset(), 0)

您可以尝试使用FancyCoverFlow作为水平选择器。它就像viewpager@berserk该库使用了我不想使用的已弃用的
GalleryView
。请将那些SimpleDataFormat作为字段,每个视图创建两个循环太多了。HI@rekire:ForecasAdapter.ITEM\u在这里的\u中心是什么?在我的例子中,它是151,因为我有301个元素。回答很好。。。。没有完全解决问题,但使滚动更好。我通过向int-top添加+1000来修复它。不会推荐它,因为它是一个丑陋的黑客,但对于那些有同样问题的人,这将是方案C或D。对于垂直,这为我做到了:linearLayoutManager.scrollToPositionWithOffset(位置,0);