android snaphelper循环,Android Studio第十八期 - Snaphelper

GravitySnapHelper是一个自定义的RecyclerView辅助类,它允许SnapHelper将视图吸附到顶部、底部、开始或结束位置。源代码实现了一个滚动监听器,当状态变为静止时,如果设置了监听器,则会触发snap事件。此外,还提供了启用最后一个可snapping项的功能,以允许在列表末尾吸附。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码已经整理好,效果如下图:

GravitySnapHelper:/*

* Copyright (C) 2016 The Android Open Source Project

* Copyright (C) 2016 Rúben Sousa

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

*      http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific languag`e governing permissions and

* limitations under the License.

*/

package com.haiersmart.sfnation.widget;

import android.support.annotation.NonNull;

import android.support.annotation.Nullable;

import android.support.v7.widget.LinearLayoutManager;

import android.support.v7.widget.LinearSnapHelper;

import android.support.v7.widget.OrientationHelper;

import android.support.v7.widget.RecyclerView;

import android.view.Gravity;

import android.view.View;

import com.haiersmart.sfnation.R;

public class GravitySnapHelper extends LinearSnapHelper {

private OrientationHelper mVerticalHelper;

private OrientationHelper mHorizontalHelper;

private int mGravity;

private boolean mIsRtlHorizontal;

private boolean mSnapLastItemEnabled;

SnapListener mSnapListener;

boolean mSnapping;

private RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() {

@Override

public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

super.onScrollStateChanged(recyclerView, newState);

if (newState == RecyclerView.SCROLL_STATE_SETTLING) {

mSnapping = false;

}

if (newState == RecyclerView.SCROLL_STATE_IDLE && mSnapping && mSnapListener != null) {

int position = getSnappedPosition(recyclerView);

if (position != RecyclerView.NO_POSITION) {

mSnapListener.onSnap(position);

}

mSnapping = false;

}

}

};

public GravitySnapHelper(int gravity) {

this(gravity, false, null);

}

public GravitySnapHelper(int gravity, boolean enableSnapLastItem) {

this(gravity, enableSnapLastItem, null);

}

public GravitySnapHelper(int gravity, boolean enableSnapLastItem, SnapListener snapListener) {

if (gravity != Gravity.START && gravity != Gravity.END

&& gravity != Gravity.BOTTOM && gravity != Gravity.TOP) {

throw new IllegalArgumentException("Invalid gravity value. Use START " +

"| END | BOTTOM | TOP constants");

}

mSnapListener = snapListener;

mGravity = gravity;

mSnapLastItemEnabled = enableSnapLastItem;

}

@Override

public void attachToRecyclerView(@Nullable RecyclerView recyclerView)

throws IllegalStateException {

if (recyclerView != null) {

if (mGravity == Gravity.START || mGravity == Gravity.END) {

mIsRtlHorizontal

= recyclerView.getContext().getResources().getBoolean(R.bool.is_rtl);

}

if (mSnapListener != null) {

recyclerView.addOnScrollListener(mScrollListener);

}

}

super.attachToRecyclerView(recyclerView);

}

@Override

public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager,

@NonNull View targetView) {

int[] out = new int[2];

if (layoutManager.canScrollHorizontally()) {

if (mGravity == Gravity.START) {

out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager), false);

} else { // END

out[0] = distanceToEnd(targetView, getHorizontalHelper(layoutManager), false);

}

} else {

out[0] = 0;

}

if (layoutManager.canScrollVertically()) {

if (mGravity == Gravity.TOP) {

out[1] = distanceToStart(targetView, getVerticalHelper(layoutManager), false);

} else { // BOTTOM

out[1] = distanceToEnd(targetView, getVerticalHelper(layoutManager), false);

}

} else {

out[1] = 0;

}

return out;

}

@Override

public View findSnapView(RecyclerView.LayoutManager layoutManager) {

View snapView = null;

if (layoutManager instanceof LinearLayoutManager) {

switch (mGravity) {

case Gravity.START:

snapView = findStartView(layoutManager, getHorizontalHelper(layoutManager));

break;

case Gravity.END:

snapView = findEndView(layoutManager, getHorizontalHelper(layoutManager));

break;

case Gravity.TOP:

snapView = findStartView(layoutManager, getVerticalHelper(layoutManager));

break;

case Gravity.BOTTOM:

snapView = findEndView(layoutManager, getVerticalHelper(layoutManager));

break;

}

}

mSnapping = snapView != null;

return snapView;

}

/**

* Enable snapping of the last item that's snappable.

* The default value is false, because you can't see the last item completely

* if this is enabled.

*

* @param snap true if you want to enable snapping of the last snappable item

*/

public void enableLastItemSnap(boolean snap) {

mSnapLastItemEnabled = snap;

}

private int distanceToStart(View targetView, OrientationHelper helper, boolean fromEnd) {

if (mIsRtlHorizontal && !fromEnd) {

return distanceToEnd(targetView, helper, true);

}

return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();

}

private int distanceToEnd(View targetView, OrientationHelper helper, boolean fromStart) {

if (mIsRtlHorizontal && !fromStart) {

return distanceToStart(targetView, helper, true);

}

return helper.getDecoratedEnd(targetView) - helper.getEndAfterPadding();

}

/**

* Returns the first view that we should snap to.

*

* @param layoutManager the recyclerview's layout manager

* @param helper        orientation helper to calculate view sizes

* @return the first view in the LayoutManager to snap to

*/

private View findStartView(RecyclerView.LayoutManager layoutManager,

OrientationHelper helper) {

if (layoutManager instanceof LinearLayoutManager) {

int firstChild = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();

if (firstChild == RecyclerView.NO_POSITION) {

return null;

}

View child = layoutManager.findViewByPosition(firstChild);

float visibleWidth;

// We should return the child if it's visible width

// is greater than 0.5 of it's total width.

// In a RTL configuration, we need to check the start point and in LTR the end point

if (mIsRtlHorizontal) {

visibleWidth = (float) (helper.getTotalSpace() - helper.getDecoratedStart(child))

/ helper.getDecoratedMeasurement(child);

} else {

visibleWidth = (float) helper.getDecoratedEnd(child)

/ helper.getDecoratedMeasurement(child);

}

// If we're at the end of the list, we shouldn't snap

// to avoid having the last item not completely visible.

boolean endOfList = ((LinearLayoutManager) layoutManager)

.findLastCompletelyVisibleItemPosition()

== layoutManager.getItemCount() - 1;

if (visibleWidth > 0.5f && !endOfList) {

return child;

} else if (mSnapLastItemEnabled && endOfList) {

return child;

} else if (endOfList) {

return null;

} else {

// If the child wasn't returned, we need to return

// the next view close to the start.

return layoutManager.findViewByPosition(firstChild + 1);

}

}

return null;

}

private View findEndView(RecyclerView.LayoutManager layoutManager,

OrientationHelper helper) {

if (layoutManager instanceof LinearLayoutManager) {

int lastChild = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();

if (lastChild == RecyclerView.NO_POSITION) {

return null;

}

View child = layoutManager.findViewByPosition(lastChild);

float visibleWidth;

if (mIsRtlHorizontal) {

visibleWidth = (float) helper.getDecoratedEnd(child)

/ helper.getDecoratedMeasurement(child);

} else {

visibleWidth = (float) (helper.getTotalSpace() - helper.getDecoratedStart(child))

/ helper.getDecoratedMeasurement(child);

}

// If we're at the start of the list, we shouldn't snap

// to avoid having the first item not completely visible.

boolean startOfList = ((LinearLayoutManager) layoutManager)

.findFirstCompletelyVisibleItemPosition() == 0;

if (visibleWidth > 0.5f && !startOfList) {

return child;

} else if (mSnapLastItemEnabled && startOfList) {

return child;

} else if (startOfList) {

return null;

} else {

// If the child wasn't returned, we need to return the previous view

return layoutManager.findViewByPosition(lastChild - 1);

}

}

return null;

}

int getSnappedPosition(RecyclerView recyclerView) {

RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();

if (layoutManager instanceof LinearLayoutManager) {

if (mGravity == Gravity.START || mGravity == Gravity.TOP) {

return ((LinearLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition();

} else if (mGravity == Gravity.END || mGravity == Gravity.BOTTOM) {

return ((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition();

}

}

return RecyclerView.NO_POSITION;

}

private OrientationHelper getVerticalHelper(RecyclerView.LayoutManager layoutManager) {

if (mVerticalHelper == null) {

mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager);

}

return mVerticalHelper;

}

private OrientationHelper getHorizontalHelper(RecyclerView.LayoutManager layoutManager) {

if (mHorizontalHelper == null) {

mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);

}

return mHorizontalHelper;

}

public interface SnapListener {

void onSnap(int position);

}

}

build.gradlecompile 'com.android.support:design:25.0.0'

compile 'com.android.support:appcompat-v7:25.0.0'

compile 'com.android.support:recyclerview-v7:25.0.0'

compile 'com.android.support:cardview-v7:25.0.0'

方法调用:recycler_view1.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));

SnapHelper snapHelperStart = new GravitySnapHelper(Gravity.TOP);

snapHelperStart.attachToRecyclerView(recycler_view1);

7b82962648d4908a91bc0799bd972017.gif

地址:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值