reclyview实现列表回弹动画效果,供大家参考,具体内容如下
1.reclyview列表布局文件
<com.example.demo1.ReboundLayout
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadingEdgeLength="30px"
android:requiresFadingEdge="horizontal"/>
</com.example.demo1.ReboundLayout>
2.item布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40px"
android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/card_item_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"/>
</LinearLayout>
3.适配adapter
public class HomeCardAdapter extends RecyclerView.Adapter<HomeCardAdapter.ViewHolder> {
private LayoutInflater mInflater;
private List<Integer> mDatas;
private OnItemClickListener mOnItemClickListener;
private Context mContext;
public HomeCardAdapter(Context context, List<Integer> datats) {
mInflater = LayoutInflater.from(context);
mDatas = datats;
mContext = context;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View arg0) {
super(arg0);
}
ImageView mImg;
}
public interface OnItemClickListener{
void onClick(int position);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener ){
this.mOnItemClickListener =onItemClickListener;
}
@Override
public int getItemCount() {
return mDatas.size();
}
/**
* 创建ViewHolder
*/
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = mInflater.inflate(R.layout.card_item,
viewGroup, false);
ViewHolder viewHolder = new ViewHolder(view);
viewHolder.mImg = (ImageView) view.findViewById(R.id.card_item_img);
return viewHolder;
}
/**
* 设置值
*/
@Override
public void onBindViewHolder(final ViewHolder viewHolder, @SuppressLint("RecyclerView")int i) {
viewHolder.mImg.setImageResource(mDatas.get(i));
if( mOnItemClickListener!= null){
viewHolder.itemView.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onClick(i);
//卡片点击动画
Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.scale_card);
viewHolder.itemView.startAnimation(animation);
}
});
}
}
}
4.自定义弹性view
public class ReboundLayout extends LinearLayout implements NestedScrollingParent {
private View mHeaderView;
private View mFooterView;
private static final int MAX_WIDTH = 200;
private View mChildView;
// 解决多点触控问题
private boolean isRunAnim;
private boolean isFlag = false;
private int mDrag = 6;//除数越大可以滑动的距离越短
public ReboundLayout(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.HORIZONTAL);
mHeaderView = new View(context);
mHeaderView.setBackgroundColor(0xfff);
mFooterView = new View(context);
mFooterView.setBackgroundColor(0xfff);
}
public boolean isFlag() {
return isFlag;
}
public void setFlag(boolean flag) {
isFlag = flag;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mChildView = getChildAt(0);
LayoutParams layoutParams = new LayoutParams(MAX_WIDTH, LayoutParams.MATCH_PARENT);
addView(mHeaderView, 0, layoutParams);
addView(mFooterView, getChildCount(), layoutParams);
// 左移
scrollBy(MAX_WIDTH, 0);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
ViewGroup.LayoutParams params = mChildView.getLayoutParams();
params.width = getMeasuredWidth();
}
/**
* 必须要复写 onStartNestedScroll后调用
*/
@Override
public void onNestedScrollAccepted(View child, View target, int axes) {
}
/**
* 返回true代表处理本次事件
*/
@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
if (target instanceof RecyclerView && !isRunAnim) {
return true;
}
return false;
}
/**
* 复位初始位置
*/
@Override
public void onStopNestedScroll(View target) {
startAnimation(new ProgressAnimation());
}
/**
* 回弹动画
*/
private class ProgressAnimation extends Animation {
// 预留
private float startProgress = 0;
private float endProgress = 1;
private ProgressAnimation() {
isRunAnim = true;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float progress = ((endProgress - startProgress) * interpolatedTime) + startProgress;
scrollBy((int) ((MAX_WIDTH - getScrollX()) * progress), 0);
if (progress == 1) {
//滑动停止
isRunAnim = false;
isFlag = false;
}
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
setDuration(200);
}
}
@Override
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int
dyUnconsumed) {
}
@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
// 如果在自定义ViewGroup之上还有父View交给我来处理
getParent().requestDisallowInterceptTouchEvent(true);
// dx>0 往左滑动 dx<0往右滑动
boolean hiddenLeft = dx > 0 && getScrollX() < MAX_WIDTH && !ViewCompat
.canScrollHorizontally(target, -1);
boolean showLeft = dx < 0 && !ViewCompat.canScrollHorizontally(target, -1);
boolean hiddenRight = dx < 0 && getScrollX() > MAX_WIDTH && !ViewCompat
.canScrollHorizontally(target, 1);
boolean showRight = dx > 0 && !ViewCompat.canScrollHorizontally(target, 1);
if (hiddenLeft || showLeft || hiddenRight || showRight) {
scrollBy(dx / mDrag, 0);
consumed[0] = dx;
}
// 限制错位问题
if (dx > 0 && getScrollX() > MAX_WIDTH && !ViewCompat.canScrollHorizontally(target, -1)) {
scrollTo(MAX_WIDTH, 0);
}
if (dx < 0 && getScrollX() < MAX_WIDTH && !ViewCompat.canScrollHorizontally(target, 1)) {
scrollTo(MAX_WIDTH, 0);
}
isFlag = true;
}
@Override
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
return false;
}
@Override
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
// 当RecyclerView在界面之内交给它自己惯性滑动
if (getScrollX() == MAX_WIDTH) {
return false;
}
return true;
}
@Override
public int getNestedScrollAxes() {
return 0;
}
/**
* 限制滑动 移动x轴不能超出最大范围
*/
@Override
public void scrollTo(int x, int y) {
if (x < 0) {
x = 0;
} else if (x > MAX_WIDTH * 2) {
x = MAX_WIDTH * 2;
}
super.scrollTo(x, y);
}
}
5.activity调用
public class MainActivity extends AppCompatActivity {
private List<Integer> mDatas;
private RecyclerView mRecyclerView;
private HomeCardAdapter mAdapter;
private ReboundLayout movingView;
private LinearLayout linearLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
mRecyclerView.setLayoutManager(linearLayoutManager);
//设置适配器
mAdapter = new HomeCardAdapter(this, mDatas);
mRecyclerView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new HomeCardAdapter.OnItemClickListener() {
@Override
public void onClick(int position) {
switch (position){
case 0:
Toast.makeText(MainActivity.this, "第"+position+"个", Toast.LENGTH_SHORT).show();
break;
case 1:
Toast.makeText(MainActivity.this, "第"+position+"个", Toast.LENGTH_SHORT).show();
break;
case 2:
Toast.makeText(MainActivity.this, "第"+position+"个", Toast.LENGTH_SHORT).show();
break;
case 3:
Toast.makeText(MainActivity.this, "第"+position+"个", Toast.LENGTH_SHORT).show();
break;
case 4:
Toast.makeText(MainActivity.this, "第"+position+"个", Toast.LENGTH_SHORT).show();
break;
case 5:
Toast.makeText(MainActivity.this, "第"+position+"个", Toast.LENGTH_SHORT).show();
break;
case 6:
Toast.makeText(MainActivity.this, "第"+position+"个", Toast.LENGTH_SHORT).show();
break;
case 7:
Toast.makeText(MainActivity.this, "第"+position+"个", Toast.LENGTH_SHORT).show();
break;
}
}
});
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull @NotNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE && movingView.isFlag()) {
if (!recyclerView.canScrollHorizontally(1)) {
//回弹动画
springAnim(movingView,-100,0,200,6);
} else if (!recyclerView.canScrollHorizontally(-1)) {
springAnim(mRecyclerView,100,0,200,6);
}
}
movingView.setFlag(false);
}
});
}
private void initData() {
movingView = findViewById(R.id.view);
linearLayout = findViewById(R.id.home_card_layout);
mRecyclerView = findViewById(R.id.rv);
mDatas = new ArrayList<>(Arrays.asList(R.drawable.home_control,R.drawable.home_navigation,R.drawable.home_media,
R.drawable.home_hvac,R.drawable.home_energy,R.drawable.home_account,R.drawable.home_iot));
}
/**
*
* @param view 执行动画的view
* @param from 幅度最大值
* @param to 结束值
* @param tension 张力
* @param friction 摩擦力(值越小 弹的次数越多 0为无限循环 参考值 4)
*/
private void springAnim(final View view,float from,float to,double tension,double friction){
SpringSystem system = SpringSystem.create();
Spring spring = system.createSpring();
spring.setCurrentValue(from);
spring.setSpringConfig(new SpringConfig(tension, friction));
spring.addListener(new SimpleSpringListener(){
@Override
public void onSpringUpdate(Spring spring) {
view.setTranslationX((float) spring.getCurrentValue());
}
});
spring.setEndValue(to);
}
}