控制平滑滚动的回收视图 [英] Control Smooth scroll in recycler view

查看:759
本文介绍了控制平滑滚动的回收视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Recyclerview与CardView。我知道如何控制速度上的列表视图。但不适合Recyclerview。

我搜索了很多中发现的类名<一href="https://developer.android.com/reference/android/support/v7/widget/RecyclerView.SmoothScroller.html">SmoothScroll.如何使用?我不知道!眼下Recyclerview默认情况下,滚动快。

编辑:

现在RecyclerView正在滚动太快。我想放慢滚动速度,以便用户可以真正下跌的平滑滚动。

活动我用

 公共类主要的扩展活动实现OnClickListener {

私人RecyclerView mRecyclerView;
私人RecyclerView.Adapter mAdapter;
私人RecyclerView.LayoutManager mLayoutManager;

LinearLayoutManager流明;

名单&LT; CONTACTINFO&GT;数据;
RelativeLayout的relUndo;

按钮btnAdd;
INT位置= 0;
CONTACTINFO删除;
处理程序隐藏;
Runnable运行;
布尔isRunning = FALSE;

LayoutM lmgr;

@覆盖
保护无效的onCreate(包savedInstanceState){
    super.onCreate(savedInstanceState);
    的setContentView(R.layout.main);

    mRecyclerView =(RecyclerView)findViewById(R.id.my_recycler_view);
    btnAdd =(按钮)findViewById(R.id.button1);

    btnAdd.setOnClickListener(本);
    lmgr =新LayoutM();

    mRecyclerView.setHasFixedSize(真正的);
    mLayoutManager = lmgr;
    mRecyclerView.setLayoutManager(mLayoutManager);
    relUndo =(RelativeLayout的)findViewById(R.id.relUndo);
    relUndo.setVisibility(View.GONE);


    数据=新的ArrayList&LT; CONTACTINFO&GT;();

    的for(int i = 0; I&LT; 100;我++){
        CONTACTINFO CI =新CONTACTINFO();
        ci.name =名称+我;
        ci.surname =姓+我;
        ci.email =电子邮件+我;
        data.add(CI);
    }
    mAdapter =新MyAdapter(数据);
    mRecyclerView.setAdapter(mAdapter);

}


公共类MyAdapter扩展
        RecyclerView.Adapter&LT; MyAdapter.ContactViewHolder&GT; {
    私人列表&LT; CONTACTINFO&GT; mDataset;

    //提供一个合适的构造函数(依赖于那种数据集)
    公共MyAdapter(名单&LT; CONTACTINFO&GT; contactList){
        mDataset = contactList;
    }

    //创建新的视图(由布局管理器调用)
    @覆盖
    公共ContactViewHolder onCreateViewHolder(ViewGroup中父母,
            INT viewType){
        查看ItemView控件= LayoutInflater.from(parent.getContext())。膨胀(
                R.layout.row_card,父母,假);

        返回新ContactViewHolder(ItemView控件);
    }

    //替换视图的内容(由布局管理器调用)
    @覆盖
    公共无效onBindViewHolder(ContactViewHolder持有人,INT位置){
        CONTACTINFO CI = mDataset.get(位置);
        holder.vName.setText(ci.name);
        holder.vSurname.setText(ci.surname);
        holder.vEmail.setText(ci.email);
        holder.vTitle.setText(ci.name ++ ci.surname);
    }

    //返回数据集的大小(由布局管理器调用)
    @覆盖
    公众诠释getItemCount(){
        返回mDataset.size();
    }

    公共类ContactViewHolder扩展RecyclerView.ViewHolder {
        受保护的TextView vName;
        受保护的TextView vSurname;
        受保护的TextView vEmail;
        受保护的TextView vTitle;

        公共ContactViewHolder(视图v){
            超级(五);
            vName =(TextView中)v.findViewById(R.id.txtName);
            vSurname =(TextView中)v.findViewById(R.id.txtSurname);
            vEmail =(TextView中)v.findViewById(R.id.txtEmail);
            vTitle =(TextView中)v.findViewById(R.id.title);
        }
    }
}

@覆盖
公共无效的onClick(视图v){
    如果(V == btnAdd){
        如果(删除!= NULL){
            data.add(位置,删除);
            mAdapter.notifyItemInserted(位置);
            mAdapter.notifyDataSetChanged();
            relUndo.setVisibility(View.GONE);
        } 其他 {
            CONTACTINFO CI =新CONTACTINFO();
            ci.name =名称增加了;
            ci.surname =姓氏加;
            ci.email =通过电子邮件添加;
            data.add(位置,CI);
            mAdapter.notifyItemInserted(位置);
            mAdapter.notifyDataSetChanged();
        }
    }
}
 

解决方案

目前还不清楚是什么的时候,你说你的意思是 smoothScroll 。你可能是指自动 smoothScrollToPosition ,它会自动滚动到指定的位置,你可以谈论手动滚动,你可以谈论扔。为求繁荣,我会尝试,现在来回答所有这些问题。

1。自动平滑滚动。

在你的布局管理器,你需要实现 smoothScrollToPosition 方法:

  @覆盖
    公共无效smoothScrollToPosition(RecyclerView recyclerView,国家的状态,INT位置)
    {
        //一个很好的想法是在一些初始化的方法创建这种情况下,只是设定在该方法中的目标位置。
        LinearSmoothScroller smoothScroller =新LinearSmoothScroller(的getContext())
        {
            @覆盖
            公众的PointF computeScrollVectorForPosition(INT targetPosition)
            {
                INT yDelta = calculateCurrentDistanceToPosition(targetPosition);
                返回新的PointF(0,yDelta);
            }

            //这是最重要的方法。这code将返回需要滚动1个像素时间。
            //这个code将请求X毫秒对于每个Y DP单位。
            @覆盖
            保护浮动calculateSpeed​​PerPixel(DisplayMetrics displayMetrics)
            {
                返回X / TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,Y,displayMetrics);
            }

        };
        smoothScroller.setTargetPosition(位置);

        startSmoothScroll(smoothScroller);
    }
 

2。放慢手动滚动。

再一次,你需要编辑你的布局管理器,这个时间 - scrollVerticallyBy 方法:

  @覆盖
    公众诠释scrollVerticallyBy(INT三角洲,回收站回收,国邦)
    {
       //超出列表的限制编写限制逻辑在这里prevent增量。

       INT prevDelta =增量;
       如果(getScrollState()== SCROLL_STATE_DRAGGING)
            增量=(int)的(增量大于0 Math.max(△* MANUAL_SCROLL_SLOW_RATIO,1):Math.min(△* MANUAL_SCROLL_SLOW_RATIO,-1));

       // MANUAL_SCROLL_SLOW_RATIO是在0(没有手动滚动)到1(正常速度)以上(更快的速度)。
       //写你的滚动逻辑code在这里,让你在给定的增量移动每个视图

        如果(getScrollState()== SCROLL_STATE_DRAGGING)
            增量= prevDelta;

        返回增量;
    }
 

编辑:在上面的方法,我称之为 getScrollState()。这是 RecyclerView 的方法。在此实现,我自定义的布局管理是一个嵌套类我自定义的 RecyclerView 。如果这不适合你,你可以尝试通过一些接口模式抢滚动状态。

3。放慢速度一扔

下面要缩小一扔速度。您将需要重写一扔方法,你RecyclerView子里面:

  @覆盖
公共布尔一扔(INT velocityX,INT velocityY)
{
     velocityY * = FLING_SCALE_DOWN_FACTOR; //(0无一扔,和1的正常一扔,或更多更快一扔)。

     返回super.fling(velocityX,velocityY);
}
 

这是我很难提供更有针对性的解决方案,因为你没有发布任何你code,或提供有关设置多的信息,但我希望这涵盖了大部分基地,将帮助您找到最好的为您解决。

I am using Recyclerview with CardView. I am aware how to control speed on list view. But not for Recyclerview.

I searched a lot in found class name SmoothScroll. How to use that? I have no Idea! Right now Recyclerview by default scroll is fast.

Edit:

Right now RecyclerView is scrolling too fast. I want to slow down scrolling speed so user can actually fell the smooth scroll.

Activity I used

public class main extends Activity implements OnClickListener {

private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;

LinearLayoutManager lm;

List<ContactInfo> data;
RelativeLayout relUndo;

Button btnAdd;
int position = 0;
ContactInfo deleted;
Handler hide;
Runnable run;
boolean isRunning = false;

LayoutM lmgr;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
    btnAdd = (Button) findViewById(R.id.button1);

    btnAdd.setOnClickListener(this);
    lmgr = new LayoutM();

    mRecyclerView.setHasFixedSize(true);
    mLayoutManager = lmgr;
    mRecyclerView.setLayoutManager(mLayoutManager);
    relUndo = (RelativeLayout) findViewById(R.id.relUndo);
    relUndo.setVisibility(View.GONE);


    data = new ArrayList<ContactInfo>();

    for (int i = 0; i < 100; i++) {
        ContactInfo ci = new ContactInfo();
        ci.name = "Name " + i;
        ci.surname = "Surname " + i;
        ci.email = "Email " + i;
        data.add(ci);
    }
    mAdapter = new MyAdapter(data);
    mRecyclerView.setAdapter(mAdapter);

}


public class MyAdapter extends
        RecyclerView.Adapter<MyAdapter.ContactViewHolder> {
    private List<ContactInfo> mDataset;

    // Provide a suitable constructor (depends on the kind of dataset)
    public MyAdapter(List<ContactInfo> contactList) {
        mDataset = contactList;
    }

    // Create new views (invoked by the layout manager)
    @Override
    public ContactViewHolder onCreateViewHolder(ViewGroup parent,
            int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.row_card, parent, false);

        return new ContactViewHolder(itemView);
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ContactViewHolder holder, int position) {
        ContactInfo ci = mDataset.get(position);
        holder.vName.setText(ci.name);
        holder.vSurname.setText(ci.surname);
        holder.vEmail.setText(ci.email);
        holder.vTitle.setText(ci.name + " " + ci.surname);
    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return mDataset.size();
    }

    public class ContactViewHolder extends RecyclerView.ViewHolder {
        protected TextView vName;
        protected TextView vSurname;
        protected TextView vEmail;
        protected TextView vTitle;

        public ContactViewHolder(View v) {
            super(v);
            vName = (TextView) v.findViewById(R.id.txtName);
            vSurname = (TextView) v.findViewById(R.id.txtSurname);
            vEmail = (TextView) v.findViewById(R.id.txtEmail);
            vTitle = (TextView) v.findViewById(R.id.title);
        }
    }
}

@Override
public void onClick(View v) {
    if (v == btnAdd) {
        if (deleted != null) {
            data.add(position, deleted);
            mAdapter.notifyItemInserted(position);
            mAdapter.notifyDataSetChanged();
            relUndo.setVisibility(View.GONE);
        } else {
            ContactInfo ci = new ContactInfo();
            ci.name = "Name Added";
            ci.surname = "Surname Added";
            ci.email = "Email Added";
            data.add(position, ci);
            mAdapter.notifyItemInserted(position);
            mAdapter.notifyDataSetChanged();
        }
    }
}

解决方案

It's unclear what you mean when you say "smoothScroll". You could be referring to the automatic "smoothScrollToPosition" which will automatically scroll to a specified position, you could be talking about manual scrolling and you could be talking about flinging. For the sake of prosperity, I will attempt to answer all of these issues now.

1. Automatic smooth scrolling.

Inside your layout manager, you need to implement the smoothScrollToPosition method:

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, State state, int position)
    {
        // A good idea would be to create this instance in some initialization method, and just set the target position in this method.
        LinearSmoothScroller smoothScroller = new LinearSmoothScroller(getContext())
        {
            @Override
            public PointF computeScrollVectorForPosition(int targetPosition)
            {
                int yDelta = calculateCurrentDistanceToPosition(targetPosition);
                return new PointF(0, yDelta);
            }

            // This is the important method. This code will return the amount of time it takes to scroll 1 pixel.
            // This code will request X milliseconds for every Y DP units.
            @Override
            protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics)
            {
                return X / TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, Y, displayMetrics);
            }

        };
        smoothScroller.setTargetPosition(position);

        startSmoothScroll(smoothScroller);
    }

2. Slowing down manual scrolling.

Once again, you need to edit your layout manager, this time - the scrollVerticallyBy method:

    @Override
    public int scrollVerticallyBy(int delta, Recycler recycler, State state)
    {
       // write your limiting logic here to prevent the delta from exceeding the limits of your list.

       int prevDelta = delta;
       if (getScrollState() == SCROLL_STATE_DRAGGING)
            delta = (int)(delta > 0 ? Math.max(delta * MANUAL_SCROLL_SLOW_RATIO, 1) : Math.min(delta * MANUAL_SCROLL_SLOW_RATIO, -1));  

       // MANUAL_SCROLL_SLOW_RATIO is between 0 (no manual scrolling) to 1 (normal speed) or more (faster speed).
       // write your scrolling logic code here whereby you move each view by the given delta

        if (getScrollState() == SCROLL_STATE_DRAGGING)
            delta = prevDelta;

        return delta;
    }

Edit: In the above method, I call "getScrollState()". This is a method of RecyclerView. In this implementation, my custom LayoutManager is a nested class of my custom RecyclerView. If this doesn't work for you, you can try to grab the scroll state via some interface pattern.

3. Slow down the fling speed

Here you want to scale down the fling velocity. You will need to override the fling method inside your RecyclerView subclass:

@Override
public boolean fling(int velocityX, int velocityY)
{
     velocityY *= FLING_SCALE_DOWN_FACTOR; // (between 0 for no fling, and 1 for normal fling, or more for faster fling).

     return super.fling(velocityX, velocityY);
}

It's difficult for me to provide a more tailored solution, since you didn't post any of your code, or provide much information about your setup, but I hope this covers most bases and will help you find the best solution for you.

这篇关于控制平滑滚动的回收视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆