ListView和Recyclerview实现滑动隐藏与显示FloatingActionButton

65 阅读3分钟

app:pressedTranslationZ:按下时的阴影大小

app:layout_anchor:设置FAB的锚点,即以哪个控件为参照设置位置,我在上面设置了listview,所以以 listview为锚点,且父类布局须为CoordinatorLayout

app:layout_anchorGravity:FAB相对于锚点的位置,

app:fabSize:FAB的大小,这里设normal,没试过mini

完整xml布局


<android.support.design.widget.CoordinatorLayout xmlns:android="schemas.android.com/apk/res/and…"

xmlns:app="schemas.android.com/apk/res-aut…"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:id="@+id/coordinator1">

<ListView

android:id="@+id/listview"

android:layout_height="match_parent"

android:layout_width="match_parent"

/>

<android.support.design.widget.FloatingActionButton

android:id="@+id/fab"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_margin="20.0dip"

app:backgroundTint="@color/colorfab"

app:elevation="5.0dip"

app:fabSize="normal"

android:src="@drawable/ic_menu_compose"

app:layout_anchor="@id/listview"

app:layout_anchorGravity="bottom|right"

app:pressedTranslationZ="10.0dip"

app:rippleColor="@color/colorfabclick"

/>

</android.support.design.widget.CoordinatorLayout>

listview结合FloatingActionButton设计


其实不管是listview还是recyclerview都是为其添加监听器检测其滑动动作,如果上滑则显示FAB(FloatingActionButton,以下都简称FAB)按钮,下滑隐藏该按钮。

一开始的效果图是用之前老师布置的作业实现的,额外设计了animal类和animaladapter,这里进行简单的arrayadapter展示

在这里插入图片描述

初始化:

private ListView listView1;

private FloatingActionButton button5_change;

private AnimatorSet hideFabAS;

private AnimatorSet showFabAS;

private boolean FAB_VISIBLE = true;

private int previousFirstVisibleItem; //记录前面第一个Item

private int lastScrollY; //记录ListView中最上面的Item(View)的上一次顶部Y坐标()

private int scrollThreshold = 2;

private int getTopItemScrollY() {

if (listView1 == null || listView1.getChildAt(0) == null) return 0;

View topItem = listView1.getChildAt(0);

return topItem.getTop();

}

Animatiorset就是为FAB添加动画,这里简单设置两个,一个显示一个隐藏。

getTopItemScrollY()是获得listview的最上面位置的Y坐标

设置FAB_VISIBLE是为了防止 设计的FAB(button5_change) 频繁执行动画,比如:

Oncreate():

List list = new ArrayList<>();

for (int i = 0; i < 150; i++) {

list.add("TestItem_" + i);

}

listView1 = (ListView)findViewById(R.id.listview);

//listView1.setAdapter(adapter);

listView1.setAdapter(new ArrayAdapter(this,android.R.layout.simple_list_item_1,list));

button5_change=(FloatingActionButton)findViewById(R.id.fab);

hideFabAS = (AnimatorSet) AnimatorInflater.loadAnimator(this,R.animator.scroll_hide_fab);

showFabAS = (AnimatorSet)AnimatorInflater.loadAnimator(this,R.animator.scroll_show_fab);

//AnimatorInflater.loadAnimator加载动画

hideFabAS.setTarget(button5_change);

showFabAS.setTarget(button5_change);

//设置动画目标控件

listView1.setOnScrollListener(new AbsListView.OnScrollListener() {

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

}

@Override

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

//listview初始化的时候会回调onScroll

if(totalItemCount == 0) {

showFabAS.start();//

return;

}

//滚动过程中:ListView中最上面一个Item还是同一个Item

if(previousFirstVisibleItem == firstVisibleItem) {

int newScrollY = getTopItemScrollY();//获得当前最上方item Y坐标

boolean isExceedThreshold = Math.abs(lastScrollY - newScrollY) > scrollThreshold;

if (isExceedThreshold) {

if (lastScrollY > newScrollY && FAB_VISIBLE == true) {//下滑

FAB_VISIBLE = false;

hideFabAS.start();//FAB执行动画

} else if(lastScrollY < newScrollY && FAB_VISIBLE == false){//上滑

FAB_VISIBLE = true;

showFabAS.start();//FAB执行动画

}

}

lastScrollY = newScrollY;

} else {

if (firstVisibleItem > previousFirstVisibleItem && FAB_VISIBLE == true){

//向下滑动时FAB执行动画

FAB_VISIBLE = false;

hideFabAS.start();

} else if(firstVisibleItem < previousFirstVisibleItem && FAB_VISIBLE == false){

//向上滑动时FAB执行动画

FAB_VISIBLE = true;

showFabAS.start();

}

lastScrollY = getTopItemScrollY();

previousFirstVisibleItem = firstVisibleItem;

}

}

});

Animator中的scroll_hide_fab.xml

<set xmlns:android="schemas.android.com/apk/res/and…"

android:ordering="together"

<objectAnimator

android:propertyName="translationY"

android:valueTo="500.00"

android:duration="200"

android:startOffset="0"

android:repeatCount="0"

android:valueType="floatType"

/>

<objectAnimator

android:propertyName="alpha"

android:valueFrom="1.00"

android:valueTo="0.00"

android:duration="200"

android:startOffset="0"

android:valueType="floatType"

android:repeatCount="0"

/>

Animator中的scroll_hide_fab.xml

<set xmlns:android="schemas.android.com/apk/res/and…"

android:ordering="together"

<objectAnimator

android:propertyName="translationY"

android:valueTo="0.0"

android:duration="100"

android:startOffset="0"

android:repeatCount="0"

android:valueType="floatType"

/>

<objectAnimator

android:propertyName="alpha"

android:valueFrom="0.00"

android:valueTo="1.00"

android:duration="100"

android:startOffset="0"

android:valueType="floatType"

android:repeatCount="0"

/>

实现这个效果从网上找了很多对listview的监听的方法,该监听方法是针对listview的所有item来对FAB进行动画执行,以下的链接给了很大帮助。

参考地址

RecyclerView结合FloatingActionButton设计


RecyclerView是新控件,较于listview可以实现更多的功能。

在使用RecyclerView时候,必须指定一个适配器Adapter和一个布局管理器LayoutManager。适配器继承RecyclerView.Adapter类。

该设计比较常见所以网上有很多实现,我是直接参考下面的链接的

参考地址

先设计了FAB动画的接口:

package com.example.myapplication_1;

public interface FABStateListener {

public void onFABHide();

public void onFABShow();

}

activity中:onFABHide()和onFABShow()是对接口的实现,onClickFAB是点击FAB回到顶端

private RecyclerView recyclerView;

private FloatingActionButton floatingActionButton;

public void onClickFAB(View view) {

recyclerView.smoothScrollToPosition(0);

}

@Override

public void onFABHide() {

RelativeLayout.LayoutParams layoutParams = (LayoutParams) floatingActionButton.getLayoutParams();

floatingActionButton.animate().translationY(floatingActionButton.getHeight() + layoutParams.bottomMargin).setInterpolator(new AccelerateInterpolator(3));

}

@Override

public void onFABShow() {

floatingActionButton.animate().translationY(0).setInterpolator(new DecelerateInterpolator(3));

}

Oncreate():

floatingActionButton = findViewById(R.id.fabr);

recyclerView = findViewById(R.id.rcv);

recyclerView.setLayoutManager(new LinearLayoutManager(this));

List list = new ArrayList<>();

for (int i = 0; i < 150; i++) {

list.add("TestItem_" + i);

}

recyclerView.setAdapter(new RecFabAdapter(list));//设置自己构建的适配器

recyclerView.addOnScrollListener(new RecScrollListener(this));

//设置自己构建的监听器

自己构建适配器 继承RecyclerView.Adapter类 重写三个方法:

onCreateViewHolder()方法,负责承载每个子项的布局。它有两个参数,其中一个是 int viewType;

onBindViewHolder()方法,负责将每个子项holder绑定数据。俩参数分别是RecyclerView.ViewHolder holder, int position;

getItemCount() 返回数组的size

package com.example.myapplication_1;

import android.support.annotation.NonNull;

import android.support.v7.widget.RecyclerView;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.TextView;

import java.util.List;

public class RecFabAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private List list;

public RecFabAdapter(List list) {

this.list = list;

}

@NonNull

@Override

public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {

View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.rev_litem, viewGroup, false);

return new MyViewHolder(view);

}

@Override

public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {

String str = list.get(position);

MyViewHolder holder = (MyViewHolder) viewHolder;

holder.textView.setText(str);

}

@Override

public int getItemCount() {

return list.size();

}

class MyViewHolder extends RecyclerView.ViewHolder {

private TextView textView;

public MyViewHolder(@NonNull View itemView) {

super(itemView);

textView = itemView.findViewById(R.id.rec_tv);//自定义布局

}

}

}

监听器 重写onScrolled方法

package com.example.myapplication_1;

import android.support.annotation.NonNull;

import android.support.v7.widget.RecyclerView;

import android.util.Log;

public class RecScrollListener extends RecyclerView.OnScrollListener {

private static final int THRESHOLD = 10;

private int distance = 0;

private FABStateListener fabStateListener;

private boolean visible = true;//是否可见

public RecScrollListener(FABStateListener hideScrollListener) {

this.fabStateListener = hideScrollListener;

}

@Override

public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {

super.onScrolled(recyclerView, dx, dy);

//Log.i("mtx","dy:"+dy);

if (distance > THRESHOLD && visible) {

//隐藏