简体   繁体   English

如何在android中滚动时放大Recycler View中心项目?

[英]How to scale up Recycler View center item while scrolling in android?

我需要在通过放大滚动时始终突出显示回收器视图中的中心项目。

You should follow this code, this helped me to scale up the center item in recycler view.您应该遵循此代码,这有助于我在回收站视图中放大中心项目。

public class CenterZoomLayoutManager extends LinearLayoutManager {

    private final float mShrinkAmount = 0.15f;
    private final float mShrinkDistance = 0.9f;

    public CenterZoomLayoutManager(Context context) {
        super(context);
    }

    public CenterZoomLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    @Override
    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        int orientation = getOrientation();
        if (orientation == VERTICAL) {
            int scrolled = super.scrollVerticallyBy(dy, recycler, state);
            float midpoint = getHeight() / 2.f;
            float d0 = 0.f;
            float d1 = mShrinkDistance * midpoint;
            float s0 = 1.f;
            float s1 = 1.f - mShrinkAmount;
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                float childMidpoint =
                        (getDecoratedBottom(child) + getDecoratedTop(child)) / 2.f;
                float d = Math.min(d1, Math.abs(midpoint - childMidpoint));
                float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0);
                child.setScaleX(scale);
                child.setScaleY(scale);
            }
            return scrolled;
        } else {
            return 0;
        }
    }

    @Override
    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
        int orientation = getOrientation();
        if (orientation == HORIZONTAL) {
            int scrolled = super.scrollHorizontallyBy(dx, recycler, state);

            float midpoint = getWidth() / 2.f;
            float d0 = 0.f;
            float d1 = mShrinkDistance * midpoint;
            float s0 = 1.f;
            float s1 = 1.f - mShrinkAmount;
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                float childMidpoint =
                        (getDecoratedRight(child) + getDecoratedLeft(child)) / 2.f;
                float d = Math.min(d1, Math.abs(midpoint - childMidpoint));
                float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0);
                child.setScaleX(scale);
                child.setScaleY(scale);
            }
            return scrolled;
        } else {
            return 0;
        }

    }
}

center horizontal view中心水平视图在此处输入图片说明

I slimmed down that solution and added the initial resize during onLayoutComplete .我精简了该解决方案并在onLayoutComplete期间添加了初始调整大小。 I didn't need vertical scrolling, so I took that part out.我不需要垂直滚动,所以我去掉了那部分。

class CenterZoomLinearLayoutManager(
    context: Context,
    private val mShrinkDistance: Float = 0.9f,
    val mShrinkAmount: Float = 0.15f
) : LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) {

    override fun onLayoutCompleted(state: RecyclerView.State?) {
        super.onLayoutCompleted(state)
        scaleChildren()
    }

    override fun scrollHorizontallyBy(dx: Int, recycler: RecyclerView.Recycler?, state: RecyclerView.State?): Int {
        return if (orientation == HORIZONTAL) {
            super.scrollHorizontallyBy(dx, recycler, state).also { scaleChildren() }
        } else {
            0
        }
    }

    private fun scaleChildren() {
        val midpoint = width / 2f
        val d1 = mShrinkDistance * midpoint
        for (i in 0 until childCount) {
            val child = getChildAt(i) as View
            val d = Math.min(d1, Math.abs(midpoint - (getDecoratedRight(child) + getDecoratedLeft(child)) / 2f))
            val scale = 1f - mShrinkAmount * d / d1
            child.scaleX = scale
            child.scaleY = scale
        }
    }
}

See https://github.com/pcholt/toy-card-carouselhttps://github.com/pcholt/toy-card-carousel

As an addendum to Mayank Garg's answer and the comments it has saying that it does not work for the first or last items , this happens when you are using this class and also adding extra padding to the list at the beginning and end in order for the first item to appear already centered.作为Mayank Garg 的回答及其评论的附录,它说它不适用于第一个或最后一个项目,当您使用此类并在开始和结束时向列表添加额外的填充时会发生这种情况,以便第一个出现的项目已经居中。 In these situations, functions like getDecoratedRight() and getDecoratedLeft() will include the extra padding in the sizes they return.在这些情况下,像getDecoratedRight()getDecoratedLeft()这样的函数将在它们返回的大小中包含额外的填充。 This messes up the calculation of the view's midpoint, and hence it won't work for the first and last items.这会扰乱视图中点的计算,因此它不适用于第一个和最后一个项目。

A solution to this is to detect if the layout manager is displaying the beginning of the list or not, and use a conditional to use a different calculation which uses one of the decorated anchors as origin but then uses the view's halved width in order to find the midpoint.对此的解决方案是检测布局管理器是否显示列表的开头,并使用条件来使用不同的计算,该计算使用装饰锚之一作为原点,然后使用视图的一半宽度来查找中点。

In other words, in Mayank's code you have:换句话说,在 Mayank 的代码中,你有:

childMidpoint =
   (getDecoratedRight(child) + getDecoratedLeft(child)) / 2.f;

You can replace this with something similar to the following:您可以将其替换为类似于以下内容的内容:

if (findFirstVisibleItemPosition() == 0 && i == 0) {
   childMidPoint = getDecoratedRight(child) - child.getWidth() / 2.f;
} else {
   childMidPoint = getDecoratedLeft(child) + child.getWidth() / 2.f;
}

In other words, this checks that the first child view is, or isn't, the first item in the adapter, and if so uses either the left or right decorated horizontal position to calculate the midpoint by subtracting or adding the item's halved width.换句话说,这会检查第一个子视图是否是适配器中的第一个项目,如果是,则使用左侧或右侧装饰的水平位置通过减去或添加项目的一半宽度来计算中点。

Another simpler alternative is:另一个更简单的选择是:

childMidpoint = child.getX() + child.getWidth() / 2.0f

But then again, you need to test if this fits other constraints you may have on your layout/views, since there is probably a reason Mayank used getDecoratedLeft() instead of getX() .但话又说回来,您需要测试这是否符合您对布局/视图可能具有的其他约束,因为 Mayank 使用getDecoratedLeft()而不是getX()可能是有原因的。

Well, following Anarchofascist and Mayank, just add this override at the biggining of Mayank code to make the effect work with the first element.好吧,按照 Anarchofascist 和 Mayank,只需在 Mayank 代码的 biggining 处添加此覆盖,即可使效果与第一个元素一起使用。

@Override
public void onLayoutCompleted(RecyclerView.State state) {
    super.onLayoutCompleted(state);

    //aqui ele executa o codigo no estado inicial, originalmente ele nao aplicava no inicio
    //este codigo é em horizontal. Para usar em vertical apagar e copiar o codigo
    int orientation = getOrientation();
    if (orientation == HORIZONTAL) {

        float midpoint = getWidth() / 2.f;
        float d0 = 0.f;
        float d1 = mShrinkDistance * midpoint;
        float s0 = 1.f;
        float s1 = 1.f - mShrinkAmount;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            float childMidpoint =
                    (getDecoratedRight(child) + getDecoratedLeft(child)) / 2.f;
            float d = Math.min(d1, Math.abs(midpoint - childMidpoint));
            float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0);
            child.setScaleX(scale);
            child.setScaleY(scale);
        }

    } else {

        float midpoint = getHeight() / 2.f;
        float d0 = 0.f;
        float d1 = mShrinkDistance * midpoint;
        float s0 = 1.f;
        float s1 = 1.f - mShrinkAmount;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            float childMidpoint =
                    (getDecoratedBottom(child) + getDecoratedTop(child)) / 2.f;
            float d = Math.min(d1, Math.abs(midpoint - childMidpoint));
            float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0);
            child.setScaleX(scale);
            child.setScaleY(scale);
        }

    }
}

This method worked for me, and the problem I solved was that when RecyclerView was created, the items on the scale were not applied to them, and let me also say that the numbers I used were based on my needs, and you based on Need to adjust the scale yourself这个方法对我有用,我解决的问题是RecyclerView创建的时候,秤上的项目没有应用到他们身上,我也说一下我用的数字是根据我的需要,你是根据Need自己调整比例

public class CenterZoomLayoutManager extends LinearLayoutManager {
private final float mShrinkAmount = 0.25f;
private final float mShrinkDistance = 2.0f;

public CenterZoomLayoutManager(Context context) {
    super(context);
}

public CenterZoomLayoutManager(Context context, int orientation, boolean reverseLayout) {
    super(context, orientation, reverseLayout);
}

public CenterZoomLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
}

@Override
public void onLayoutCompleted(RecyclerView.State state) {
    super.onLayoutCompleted(state);
    scaleChild();
}

@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
    int orientation = getOrientation();
    if (orientation == HORIZONTAL) {
        scaleChild();
        return super.scrollHorizontallyBy(dx, recycler, state);
    } else {
        return 0;
    }
}

private void scaleChild() {
    float midPoint = getWidth() / 2.f;
    float d1 = mShrinkDistance * midPoint;
    for (int i = 0; i < getChildCount(); i++) {
        View child = getChildAt(i);
        float childMidPoint = (getDecoratedRight(child) + getDecoratedLeft(child)) / 2f;
        float d = Math.min(d1, Math.abs(midPoint - childMidPoint));
        float scale = 1.05f - mShrinkAmount * d / d1;
        child.setScaleY(scale);
        child.setScaleX(scale);
    }
}

} }

Be sure to call the scaleChild method in onLayoutCompleted .请务必在onLayoutCompleted调用 scaleChild 方法。 To apply the scale to items when the RecyclerView layout is created.在创建 RecyclerView 布局时将比例应用于项目。 Not just when scrolling.不仅仅是在滚动时。 This is an important point这是一个重要的点

@Override
public void onLayoutCompleted(RecyclerView.State state) {
    super.onLayoutCompleted(state);
    scaleChild();
}

The next important point is to use the scaleChild() method before returning super.scrollHorizontallyBy (dx, recycler, state) .下一个重点是在returning super.scrollHorizontallyBy (dx, recycler, state)之前使用scaleChild()方法。 Call.称呼。 Until scrolling is done.直到滚动完成。 The scale is done each time on the item每次在项目上完成规模

@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
    int orientation = getOrientation();
    if (orientation == HORIZONTAL) {
        scaleChild();
        return super.scrollHorizontallyBy(dx, recycler, state);
    } else {
        return 0;
    }
}

Eventually, this became my program output最终,这成为了我的程序输出在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在Android中点击向下/向上缩小/放大回收器视图卡项目? - How to scale down/up recycler view card item on click down/up in Android? 滚动时的回收者视图项目淡出动画 - Recycler view item fadeout animation while scrolling Recycler视图 - 滚动时调整项目视图的大小(对于旋转木马效果) - Recycler view - resizing item view while scrolling (for carousel like effect) 滚动时如何使用回收者视图识别节适配器的子项的位置 - How to identify the position of child item of section adapter using recycler view while scrolling 回收商查看中心选定的项目 - recycler view center selected item Android Espresso如何在Recycler View中单击Recycler View中的项目? - How Android Espresso click an item in Recycler View inside Recycler View? Android:回收器视图项目中的图像在快速滚动时会随机播放很多 - Android: Images in recycler view item shuffle a lot on scrolling fast 回收站视图滚动混乱 - Recycler View Scrolling messed up 如何通过位置android在回收器视图中突出显示项目 - How to highlight a item in recycler view by position android 选择时如何将项目设置为回收站视图的中心 - How to set item to center of Recycler view when selected
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM