CoordinatorLayout实现底部菜单滑动显示与隐藏

国际惯例:效果图(来自网络,侵删)

其实主要用的就是CoordinatorLayout+Behavior

首先自定义Behavior

[java]  view plain  copy
  1. import android.animation.Animator;  
  2. import android.content.Context;  
  3. import android.support.annotation.NonNull;  
  4. import android.support.design.widget.CoordinatorLayout;  
  5. import android.support.v4.view.ViewCompat;  
  6. import android.support.v4.view.animation.FastOutSlowInInterpolator;  
  7. import android.util.AttributeSet;  
  8. import android.view.View;  
  9. import android.view.ViewPropertyAnimator;  
  10. import android.view.animation.Interpolator;  
  11.   
  12. /** 
  13.  * 作者:yedajiang44 
  14.  * 时间 2018-01-11 16:47 
  15.  * 说明:自定义Behavior 
  16.  */  
  17.   
  18. public class BottomBarBehavior extends CoordinatorLayout.Behavior<View> {  
  19.     private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();  
  20.   
  21.     private float viewY;//控件距离coordinatorLayout底部距离  
  22.     private boolean isAnimate;//动画是否在进行  
  23.   
  24.     public BottomBarBehavior(Context context, AttributeSet attrs) {  
  25.         super(context, attrs);  
  26.     }  
  27.   
  28.     /** 
  29.      * 有嵌套滑动到来了,问下该Behavior是否接受嵌套滑动 
  30.      * 
  31.      * @param coordinatorLayout 当前的CoordinatorLayout 
  32.      * @param child             该Behavior对应的View 
  33.      * @param directTargetChild 我的理解是在CoordinateLayout下作为父View,而该View的子类是Tager的那个View,也就是Target的父View),因为我测试用ViewPager包裹了RecycleView后该参数返回Viewpager,如果没有包裹参数返回的是RecycleView 
  34.      * @param target            具体嵌套滑动的那个子类 
  35.      * @param nestedScrollAxes  支持嵌套滚动轴。水平方向,垂直方向,或者不指定 
  36.      * @param type              导致此滚动事件的输入类型 
  37.      * @return 是否接受该嵌套滑动 
  38.      */  
  39.   
  40.     @Override  
  41.     public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int nestedScrollAxes, @ViewCompat.NestedScrollType int type) {  
  42.         if (child.getVisibility() == View.VISIBLE && viewY == 0) {  
  43.             //获取控件距离父布局(coordinatorLayout)底部距离  
  44.             viewY = coordinatorLayout.getHeight() - child.getY();  
  45.         }  
  46.   
  47.         //ViewCompat是一个兼容类,在android5.0之前的API为了实现新的效果  
  48.         //避免出错使用ViewCompat.xxxx方法可以解决出现低版本错误的问题  
  49.         return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;//判断是否竖直滚动  
  50.     }  
  51.   
  52.   
  53.     /** 
  54.      * 在嵌套滑动的子View未滑动之前准备滑动的情况  (待修改) 
  55.      * 
  56.      * @param coordinatorLayout 此行为与关联的视图的父级CoordinatorLayout 
  57.      * @param child             该Behavior对应的View 
  58.      * @param target            具体嵌套滑动的那个子类 
  59.      * @param dx                水平方向嵌套滑动的子View想要变化的距离 
  60.      * @param dy                垂直方向嵌套滑动的子View想要变化的距离 
  61.      * @param consumed          这个参数要我们在实现这个函数的时候指定,回头告诉子View当前父View消耗的距离 consumed[0] 水平消耗的距离,consumed[1] 垂直消耗的距离 好让子view做出相应的调整 
  62.      * @param type              导致此滚动事件的输入类型 
  63.      */  
  64.     @Override  
  65.     public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {  
  66.         super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);  
  67.         //dy大于0是向上滚动 小于0是向下滚动,判断的时候尽量不要判断是否大于等于或者小于等于0,否则可能会影响点击事件  
  68.         //System.out.println(dy);  
  69.         if (type == ViewCompat.TYPE_TOUCH) {  
  70.             if (dy > 20 && !isAnimate && child.getVisibility() == View.VISIBLE) {  
  71.                 hide(child);  
  72.             } else if (dy < 20 && !isAnimate && child.getVisibility() == View.INVISIBLE) {  
  73.                 show(child);  
  74.             }  
  75.         }  
  76.     }  
  77.   
  78.     //隐藏时的动画  
  79.     private void hide(final View view) {  
  80.         ViewPropertyAnimator animator = view.animate().translationY(viewY).setInterpolator(INTERPOLATOR).setDuration(500);  
  81.   
  82.         animator.setListener(new Animator.AnimatorListener() {  
  83.             @Override  
  84.             public void onAnimationStart(Animator animator) {  
  85.                 isAnimate = true;  
  86.             }  
  87.   
  88.             @Override  
  89.             public void onAnimationEnd(Animator animator) {  
  90.                 view.setVisibility(View.INVISIBLE);  
  91.                 isAnimate = false;  
  92.             }  
  93.   
  94.             @Override  
  95.             public void onAnimationCancel(Animator animator) {  
  96.                 show(view);  
  97.             }  
  98.   
  99.             @Override  
  100.             public void onAnimationRepeat(Animator animator) {  
  101.             }  
  102.         });  
  103.         animator.start();  
  104.     }  
  105.   
  106.     //显示时的动画  
  107.     private void show(final View view) {  
  108.         ViewPropertyAnimator animator = view.animate().translationY(0).setInterpolator(INTERPOLATOR).setDuration(500);  
  109.         animator.setListener(new Animator.AnimatorListener() {  
  110.             @Override  
  111.             public void onAnimationStart(Animator animator) {  
  112.                 view.setVisibility(View.VISIBLE);  
  113.                 isAnimate = true;  
  114.             }  
  115.   
  116.             @Override  
  117.             public void onAnimationEnd(Animator animator) {  
  118.                 isAnimate = false;  
  119.             }  
  120.   
  121.             @Override  
  122.             public void onAnimationCancel(Animator animator) {  
  123.                 hide(view);  
  124.             }  
  125.   
  126.             @Override  
  127.             public void onAnimationRepeat(Animator animator) {  
  128.             }  
  129.         });  
  130.         animator.start();  
  131.     }  
  132.   
  133. }  

自定义好了Behavior之后就需要在layout布局文件里使用了

layout布局:

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"  
  4.     xmlns:tools="http://schemas.android.com/tools"  
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent">  
  7.   
  8.     <android.support.design.widget.AppBarLayout  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="wrap_content"  
  11.         android:fitsSystemWindows="true"  
  12.         android:minHeight="?attr/actionBarSize"  
  13.         android:theme="@style/AppTheme.AppBarOverlay">  
  14.   
  15.         <android.support.v7.widget.Toolbar  
  16.             android:id="@+id/activity_dyeOrder_detail_toolbar"  
  17.             android:layout_width="match_parent"  
  18.             android:layout_height="?attr/actionBarSize"  
  19.             android:background="?attr/colorPrimary"  
  20.             android:minHeight="?attr/actionBarSize"  
  21.             app:layout_scrollFlags="scroll|enterAlways"  
  22.             app:navigationIcon="@mipmap/ic_arrow_back_white_24dp"  
  23.             app:popupTheme="@style/AppTheme.PopupOverlay"  
  24.             app:title="@string/dyeOrderDetail" />  
  25.     </android.support.design.widget.AppBarLayout>  
  26.   
  27.   
  28.     <android.support.v4.widget.SwipeRefreshLayout  
  29.         android:id="@+id/swipeRefreshLayout"  
  30.         android:layout_width="match_parent"  
  31.         android:layout_height="match_parent"  
  32.         app:layout_behavior="@string/appbar_scrolling_view_behavior">  
  33.   
  34.         <android.support.v7.widget.RecyclerView  
  35.             android:id="@+id/dyeMessageList"  
  36.             android:layout_width="match_parent"  
  37.             android:layout_height="match_parent"  
  38.             android:descendantFocusability="beforeDescendants"  
  39.             android:scrollbars="vertical"  
  40.             tools:listitem="@layout/recycle_no_dye_message_entry_list" />  
  41.   
  42.     </android.support.v4.widget.SwipeRefreshLayout>  
  43.   
  44.     <LinearLayout  
  45.         android:id="@+id/addLayout"  
  46.         android:layout_width="match_parent"  
  47.         android:layout_height="?attr/actionBarSize"  
  48.         android:gravity="center"  
  49.         android:orientation="horizontal"  
  50.         android:background="@color/white"  
  51.         app:layout_behavior="BottomBarBehavior"  
  52.         app:layout_anchor="@id/swipeRefreshLayout"  
  53.         app:layout_anchorGravity="bottom|end">  
  54.         <TextView  
  55.             android:id="@+id/add"  
  56.             android:layout_width="wrap_content"  
  57.             android:layout_height="wrap_content"  
  58.             android:layout_gravity="center_vertical"  
  59.             android:text="底部菜单" />  
  60.     </LinearLayout>  
  61.   
  62. </android.support.design.widget.CoordinatorLayout>  

需要注意的是app:layout_behavior="BottomBarBehavior"中的BottomBarBehavior如果不在根目录需要加上包名
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android实现购物车底部滑动菜单可以使用BottomSheetDialog配合RecyclerView实现,具体步骤如下: 1.在XML布局文件中添加RecyclerView控件和底部操作栏布局。 2.创建RecyclerView的Adapter和ViewHolder,实现列表项的展示和点击事件。 3.在Activity或Fragment中初始化RecyclerView控件和底部操作栏布局,并设置RecyclerView的Adapter。 4.创建BottomSheetDialog实例,将底部操作栏布局作为参数传入。 5.在BottomSheetDialog中设置RecyclerView的Adapter和点击事件。 6.运行程序,查看效果。 示例代码: activity_main.xml ``` <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"/> <LinearLayout android:id="@+id/bottom_sheet" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <!-- 底部操作栏布局 --> </LinearLayout> ``` MainActivity.java ``` public class MainActivity extends AppCompatActivity { private RecyclerView recyclerView; private View bottomSheet; private BottomSheetDialog bottomSheetDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(new MyAdapter()); bottomSheet = findViewById(R.id.bottom_sheet); bottomSheetDialog = new BottomSheetDialog(this); bottomSheetDialog.setContentView(bottomSheet); bottomSheetDialog.setCancelable(true); bottomSheetDialog.setCanceledOnTouchOutside(true); recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, recyclerView, new RecyclerItemClickListener.OnItemClickListener() { @Override public void onItemClick(View view, int position) { // 处理列表项的点击事件 bottomSheetDialog.show(); } })); } private static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> { @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_my, parent, false); return new MyViewHolder(view); } @Override public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { // 设置列表项的展示内容和点击事件 } @Override public int getItemCount() { return 10; } } private static class MyViewHolder extends RecyclerView.ViewHolder { private TextView textView; MyViewHolder(@NonNull View itemView) { super(itemView); textView = itemView.findViewById(R.id.text_view); } } } ``` 注意:以上代码中的布局文件和ViewHolder仅作为示例,具体实现应根据需求进行调整。另外,RecyclerItemClickListener可以自己实现,也可以使用第三方库实现
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值