热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

AndroidBottomSheet效果的两种实现方式

这篇文章主要介绍了AndroidBottomSheet效果的两种实现方式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

本文介绍了Android BottomSheet效果的两种实现方式,分享给大家,具体如下:

BottomSheet效果

BottomSheet的效果是指从屏幕底部向上滑的效果,是MaterialDesign风格的一种,视觉效果如下:

BottomSheet效果

实现这种效果有几种不同的方式,如果是在一个固定的页面上添加这种效果,可以在该页面布局中添加BoottomSheet相关的控件。如果是作为通用控件来提供给不同页面使用,则可以使用BottomSheetDialog实现,本文将对两种方法进行讲解,其中会讲到一些使用上的细节,处理不好这些细节,会出现非常怪异的效果。

单页面添加BottomSheet效果

首先引入依赖包:

compile 'com.android.support:design:27.1.1'

页面布局如下:

<&#63;xml version="1.0" encoding="utf-8"&#63;>


  
    

    
  

  

    

    
  

根布局需要使用CoordinatorLayout,同时在其直接子布局——这里是NestedScrollView——里添加behavior app:layout_behavior = "@string/bottom_sheet_behavior" 。很多文章说指定behavior的控件必须是NestedScrollView,这是错误的,实际上任何view或viewgroup都可以。该behavior配合CoordinateLayout就可以实现behavior所在控件的上滑效果。如果需要上滑的布局展示的时候先漏出一部分,如上面视频所示,可以通过设置 app:behavior_peekHeight 实现,它用来指定漏出的高度。

在代码部分,首先获取NestedScrollView的behavior,然后通过behavior控制底部卡片什么时候弹出,同时会有一些状态回调函数可供调用。

public class BrowserActivity extends AppCompatActivity {
  private NestedScrollView nestedScrollView;
  private BottomSheetBehavior behavior;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.browser_layout);

    nestedScrollView = (NestedScrollView) findViewById(R.id.nested_scroll_view);
    behavior = BottomSheetBehavior.from(nestedScrollView);
    behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
      @Override
      public void onStateChanged(@NonNull View bottomSheet, int newState) {
        //这里是bottomSheet 状态的改变
      }

      @Override
      public void onSlide(@NonNull View bottomSheet, float slideOffset) {
        //这里是拖拽中的回调,根据slideOffset可以做一些动画
      }
    });
  }

  public void showBottomSheet() {
    behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
  }
}

通过这种方式可以在特定的页面添加底部上滑的效果。

BottomSheetDialog实现通用效果

BottomSheetDialog是BottomSheet效果实现的一种更加通用的方法,比如我们需要在不同的页面实现长按文本弹出卡片列表效果,下面给出实现。

我们集成BottomSheetDialog实现自定义的Dialog,其布局如下:

<&#63;xml version="1.0" encoding="utf-8"&#63;>


  

    
    
  

注意,这里最外层布局需要是 NestedScrollView ,而 不能是CoordinateLayout ,因为BottomSheetDialog本身已经有个CoordinateLayout根布局,它会把你的布局文件包裹起来,如果你在自己的布局里把最外层布局写成CoordinateLayout,会导致底部上滑的卡片,在下滑消失后屏幕依旧变暗的问题,这是因为整个布局变成了两个CoordinateLayout嵌套,下滑的时候里面的CoordinateLayout滑出屏幕,但外层的CoordinateLayout仍然在展示。通过查阅BottomSheetDialog源码可以看出,它是这样包裹你的布局文件的:

public class BottomSheetDialog extends AppCompatDialog {
  ...
  @Override
  public void setContentView(@LayoutRes int layoutResId) {
    super.setContentView(wrapInBottomSheet(layoutResId, null, null));
  }
  
  private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) {
    final FrameLayout cOntainer= (FrameLayout) View.inflate(getContext(),
        R.layout.design_bottom_sheet_dialog, null);
    final CoordinatorLayout coordinator =
        (CoordinatorLayout) container.findViewById(R.id.coordinator);
    if (layoutResId != 0 && view == null) {
      view = getLayoutInflater().inflate(layoutResId, coordinator, false);
    }
    FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(R.id.design_bottom_sheet);
    mBehavior = BottomSheetBehavior.from(bottomSheet);
    mBehavior.setBottomSheetCallback(mBottomSheetCallback);
    mBehavior.setHideable(mCancelable);
    if (params == null) {
      bottomSheet.addView(view);
    } else {
      bottomSheet.addView(view, params);
    }
    // We treat the CoordinatorLayout as outside the dialog though it is technically inside
    coordinator.findViewById(R.id.touch_outside).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        if (mCancelable && isShowing() && shouldWindowCloseOnTouchOutside()) {
          cancel();
        }
      }
    });
    ...
    return container;
  }
  ...
}

所以,BottomSheetDialog本身的布局实际如下:

BottomSheetDialog页面布局

我们可以看到最外层是FrameLayout,里面有个CoordinateLayout,CoordinateLayout里面有个直接子布局FrameLayout,该CoordinateLayout指定了Behavior,最里面才是用户自定义的布局,所以不应该在自定义布局里再添加CoordinateLayout,也不应该再次指定Behavior,直接摆放你的内容就行。

我们的自定义布局如下:

<&#63;xml version="1.0" encoding="utf-8"&#63;>


  

    
    
  

布局的核心是一个ListView,注意,由于ListView和behavior都需要处理滑动事件,所以直接使用ListView会导致滑动冲突,解决办法是采用ScrollView嵌套ListView实现,同时使用自定义的ListView将所有列表项展开。

自定义的NestViewEmbeddedListView如下:

public static class NestViewEmbeddedListView extends ListView {
    public NestViewEmbeddedListView(android.content.Context context, android.util.AttributeSet attrs){
      super(context, attrs);
    }
    /**
     * 设置不滚动
     */
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
      int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
          MeasureSpec.AT_MOST);
      super.onMeasure(widthMeasureSpec, expandSpec);

    }
  }

自定义的BottomSheetDialog代码如下:

public class CustomBottomSheetDialogForWebView extends BottomSheetDialog {
  private Context context;
  private NestViewEmbeddedListView listView;
  private NerResult nerResult;
  private CardListAdapter cardListAdapter = new CardListAdapter();

  public CustomBottomSheetDialogForWebView(@NonNull Context context, NerResult nerResult) {
    super(context);
    this.cOntext= context;
    this.nerResult = nerResult;
    createView();
  }

  public void createView() {
    View bottomSheetView = getLayoutInflater().inflate(R.layout.webview_bottom_sheet_layout, null);
    setContentView(bottomSheetView);

    // 注意:这里要给layout的parent设置peekHeight,而不是在layout里给layout本身设置,下面设置背景色同理,坑爹!!!
    BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(((View) bottomSheetView.getParent()));
    bottomSheetBehavior.setPeekHeight(730);

    ((View) bottomSheetView.getParent()).setBackgroundColor(context.getResources().getColor(R.color.transparent));
    listView = bottomSheetView.findViewById(R.id.card_list_view);

    cardListAdapter.setNerItems(nerResult);
    listView.setAdapter(cardListAdapter);
  }
}

这里需要注意的就是,设置背景透明和获取Behavior都是对自定义布局的父布局,也就是bottomSheetView.getParent()进行。最终的效果就是下面的效果:

BottomSheet效果

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 本文将介绍如何在混合开发(Hybrid)应用中实现Native与HTML5的交互,包括基本概念、学习目标以及具体的实现步骤。 ... [详细]
  • 作为一名在大型手机游戏公司工作的程序员,尽管主要负责游戏逻辑和内容的开发,但对iOS底层开发接触较少。现在有了iPhone和可以虚拟MAC环境的电脑,希望能找到有效的iOS开发学习路径。 ... [详细]
  • 当前,众多初创企业对全栈工程师的需求日益增长,但市场中却存在大量所谓的“伪全栈工程师”,尤其是那些仅掌握了Node.js技能的前端开发人员。本文旨在深入探讨全栈工程师在现代技术生态中的真实角色与价值,澄清对这一角色的误解,并强调真正的全栈工程师应具备全面的技术栈和综合解决问题的能力。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • 解决JAX-WS动态客户端工厂弃用问题并迁移到XFire
    在处理Java项目中的JAR包冲突时,我们遇到了JaxWsDynamicClientFactory被弃用的问题,并成功将其迁移到org.codehaus.xfire.client。本文详细介绍了这一过程及解决方案。 ... [详细]
  • 本文介绍如何通过SSH协议使用Xshell远程连接到Ubuntu系统。为了实现这一目标,需要确保Ubuntu系统已安装并配置好SSH服务器,并保证网络连通性。 ... [详细]
  • 优化局域网SSH连接延迟问题的解决方案
    本文介绍了解决局域网内SSH连接到服务器时出现长时间等待问题的方法。通过调整配置和优化网络设置,可以显著缩短SSH连接的时间。 ... [详细]
  • 本文介绍如何使用布局文件在Android应用中排列多行TextView和Button,使其占据屏幕的特定比例,并提供示例代码以帮助理解和实现。 ... [详细]
  • 本文介绍了Android开发中Intent的基本概念及其在不同Activity之间的数据传递方式,详细展示了如何通过Intent实现Activity间的跳转和数据传输。 ... [详细]
  • 本文详细介绍了如何在Android应用中处理和使用Cookie,包括登录时获取Cookie并将其存储,以及在WebView中同步这些Cookie以保持用户会话。 ... [详细]
  • 本文探讨了在安卓设备上的微信H5环境中,如何解决长按图片时无法保存或分享Base64编码图片及Blob形式图片的问题,并提供了有效的解决方案。 ... [详细]
  • 在开发一款应用程序时,我需要向用户提供一系列URL列表。为了提高用户体验,计划根据Wi-Fi状态预先加载这些URL,以便用户在点击时能够迅速访问内容,特别是在连接到Wi-Fi的情况下。 ... [详细]
  • 本文详细介绍了在CentOS 7上构建DNS解析服务器的步骤与配置方法。DNS系统不仅负责将主机名(域名)转换为相应的IP地址(正向解析),还能够根据IP地址反查主机名(反向解析)。此外,文章还探讨了不同类型的DNS服务器,如缓存域名服务器的作用和配置要点。通过本指南,读者可以全面了解并成功搭建一个高效稳定的DNS解析环境。 ... [详细]
  • 本文出处:炎之铠csdn博客:http:blog.csdn.nettotond炎之铠邮箱:yanzhikai_yjk@qq.com本文原创,转载请注明本出处!前言 ... [详细]
  • Android工程师最容易遇到4个瓶颈是什么?附带学习经验
    一些感悟穷人的一次失败,为了还债可能一辈子都翻不了身,为还债一辈子送外卖。你将不再会有精力去思考和投机。穷人的失败可能断送了他所有暴富的机遇和时间&# ... [详细]
author-avatar
小熊2502872357
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有