本文正在参加「金石方案 . 瓜分6万现金大奖」
前言
跟着工作的不断深入,作者最近触摸到了给APP换UI的需求,看着花里胡哨的新UI,想起了我之前无意在某规划网站上碰到的新词——高级规划感,紧接着,作者又在开发中发现了Google提出的Material Design,这个在14年就提出的界面规划言语,与高级规划感这个词正所谓相得益彰。
正篇
安卓中的Material Design
作为Google旗下的一员——安卓,则是将其一些最具代表性一些控件和作用封装在Material库,这就让咱们开发者能够在不了解Material Design的情况下,也很容易将自己的运用Material化,当然现在在AndroidX库中的一些组件也能够完成一些Material Design的作用。
运用原因
前言说到,作者是工作中更换UI需求的时分真正触摸到Material Design的,其实便是因为我需求一个运用其中一个控件,这个便是本篇要说的内容——BottomSheetDialogFragment。
BottomSheetDialogFragment组件
介绍
其中这个组件在Material Design中分属Bottom Sheets:
其实它还有个兄弟叫BottomSheetDialog,不过我在项目中没有具体运用,这兄弟俩在官网中的所示承继关系如下:
而MD风格的底部弹窗
,比自界说dialog
或popupwindow
运用更简略,功能也更为丰厚,而我正好需求它的底部向上滑动的这个作用,而经过查询许多资料,发现BottomSheetDialogFragment的底部出现到中间停顿,然后再向上能够拖动的作用完美契合我的需求,并且运用起来更简略,故采用该办法。
运用办法
首先运用该底部弹窗款式的第一步便是需求导入Material库:
implementation 'com.google.android.material:material:1.7.0'
增加好后Sync Gradle成功后,咱们就能够在项目中增加BottomSheetDialogFragment了,很简略,和正常写承继DialogFragment的Dialog相同,因为在上述中咱们看到了其承继关系,BottomSheetDialogFragment是承继自AppCompatDialogFragment,而
AppCompatDialogFragment又是承继自DialogFragment。如此一来,因为BottomSheetDialogFragment是DialogFragment的子类,故它具有DialogFragment的一切特性。
下面说一下Kotlin的写法
作者没有运用ViewBinding,而是运用kotlin-android-extensions插件的,因为省去许多功夫:
id 'kotlin-android-extensions'
假如想运用最新推荐的ViewBinding,能够去看看郭婶的文章(kotlin-android-extensions插件也被废弃了?扶我起来 – ())
完成需求
Dialog部分的完成代码:
class DialogMore : BottomSheetDialogFragment() {
private var height : Int = 0
fun newInstance(): DialogMore {
return DialogMore()
}
fun setDialogHeight(height: Int): DialogMore {
this.height = height
return this
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, R.style.StyleBottomSheetDialogBg)
}
override fun onStart() {
super.onStart()
//拿到系统的 bottom_sheet
val bottomSheetDialog = (dialog as BottomSheetDialog?)!!
val view =
bottomSheetDialog.delegate.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)!!
val behavior = BottomSheetBehavior.from(view)
//设置弹出高度
behavior.peekHeight = height
view.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
behavior.isHideable = false
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
val view = LayoutInflater.from(context).inflate(R.layout.layout_item_dialog_more, null)
dialog.setContentView(view)
view.vDownClose.setOnClickListener {
dismiss()
}
return dialog
}
}
能够看到,这部分完成代码和咱们平时写底部弹窗办法差不多,不过咱们在onStar()办法能够运用BottomSheetBehavior去操控弹窗本身的行为,比如高度操控和一些弹窗的特点设置
在onCreateDialog办法中咱们把弹窗布局加进去,运用setContentView()办法获取到布局,必定要写该办法,否则咱们在获取BottomSheetBehavior的时分* val behavior = BottomSheetBehavior.from(view)*这句会报空
而咱们的弹窗需求顶部圆角,且去除背景阴影,所以增加了款式:
<!--完成BottomSheetDialog圆角作用 且无背景阴影-->
<style name="StyleBottomSheetDialogBg" parent="Theme.Design.Light.BottomSheetDialog">
<item name="bottomSheetStyle">@style/StyleBottomSheetStyleWrapper</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
<style name="StyleBottomSheetStyleWrapper" parent="Widget.Design.BottomSheet.Modal">
<item name="android:background">@android:color/transparent</item>
</style>
该当地款式在Dialog完成代码处调用,在onCreate办法中运用setStyle()办法。
此外,咱们还需求在自己的布局中增加圆角:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners
android:topLeftRadius="15dp"
android:topRightRadius="15dp" />
<solid android:color="@color/white" />
</shape>
款式能够增加在咱们界说的弹窗布局最外层布局
Dialog样例布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_sheet_dialog_bg"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingTop="10dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:gravity="center"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/vDownClose"
android:layout_width="48dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_gravity="center"
android:src="@drawable/vector_invite_comment_close" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/vTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="More Content"
android:textColor="@color/black"
android:textSize="16sp"
android:textStyle="bold" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/vPositionEdit"
android:layout_width="48dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:text=""
android:textColor="@color/black"
android:textSize="16sp" />
</LinearLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/vNsPosition"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/llPtz"
android:layout_width="match_parent"
android:layout_height="8dp"
android:gravity="center"
android:orientation="horizontal">
</LinearLayout>
<LinearLayout
android:id="@+id/vLlPosition"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="300dp"
android:src="@mipmap/ic_more_content"
android:scaleType="fitCenter"/>
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="1.能够弹出弹窗,且弹窗能够继续拉到顶部。"
android:textSize="14dp"
android:textColor="#FF666666"/>
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="2.制止下拉封闭弹窗,使下滑到固定方位后不会再动,封闭弹窗运用封闭按钮。"
android:textSize="14sp"
android:textColor="#FF666666"/>
</LinearLayout>
<LinearLayout
android:id="@+id/vLlNoPosition"
android:layout_width="match_parent"
android:layout_height="277dp"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/vNoPositionText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:text="无更多内容"
android:textSize="14sp"
android:textColor="#FF666666"/>
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
假如怕弹窗内部与外面的触控作用产生冲突,最简略的便是运用NestedScrollView控件,而不是普通的ScrollView布局
Activity的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="56dp"
android:layout_height="56dp"
android:orientation="horizontal"
android:gravity="center">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="16dp"
android:layout_height="match_parent"
android:src="@drawable/vector_arrow_back"
android:scaleType="fitCenter"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="弹窗样例"
android:textColor="@color/black"
android:textSize="16sp"
app:autoSizeMaxTextSize="16sp"
app:autoSizeMinTextSize="8dp"
app:autoSizeTextType="uniform"
android:maxLines="1"/>
</LinearLayout>
<LinearLayout
android:layout_width="56dp"
android:layout_height="56dp" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_play_demo"
android:scaleType="center"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_weight="1"
android:src="@mipmap/ic_top_up"
android:scaleType= "fitCenter"/>
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_weight="1"
android:src="@mipmap/ic_transfer"
android:scaleType= "fitCenter"/>
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_weight="1"
android:src="@mipmap/ic_withdraw"
android:scaleType= "fitCenter"/>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/vMore"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_weight="1"
android:src="@mipmap/ic_more"
android:scaleType= "fitCenter"/>
</LinearLayout>
<LinearLayout
android:id="@+id/vllSize"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical"/>
</LinearLayout>
还有在Activity完成调用的代码:
class MainActivity : AppCompatActivity() {
private var dialogHeight : Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
// 获取dialog的高度
dialogHeight = vllSize.measuredHeight
// 获取dialog的高度
Log.d( "MainActivity" ,"height = $dialogHeight")
}
override fun onResume() {
super.onResume()
vMore.setOnClickListener {
val dialog = DialogMore().newInstance()
.setDialogHeight(dialogHeight)
val ft: FragmentTransaction =
supportFragmentManager.beginTransaction()
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
dialog.show(ft, "DialogMore")
}
}
}
经过测量vllSize控件(剩余底部)的高度,咱们能够将弹窗第一次弹窗的高度设置到这,当然高度能够由你恣意设置,
在Dialog完成代码中:
override fun onStart() {
super.onStart()
//拿到系统的 bottom_sheet
val bottomSheetDialog = (dialog as BottomSheetDialog?)!!
val view =
bottomSheetDialog.delegate.findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)!!
val behavior = BottomSheetBehavior.from(view)
//设置弹出高度
behavior.peekHeight = height
view.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
behavior.isHideable = false
}
view.layoutParams.height咱们设置了第2次可把弹窗拉动到整个屏幕上
本文中完成的弹窗制止了相信滑动封闭弹窗,所以不会滑到底部,代码是Dialog完成中的特点操控,不写默以为true向下滑动封闭弹窗,false表示制止该方式封闭弹窗:
behavior.isHideable = false
最终作用展现:
该作用中体现出的作用便是咱们的弹窗变得更具有灵动感,不再感到页面只要一层,愈加立体,不过单看这个弹窗作用并不明显,在其他组件上才更杰出:
比如在悬浮球(Buttons: floating action button)上
还有背板规划(Backdrop):
总结
本来想分一下文章来阐明的,但评论区直接爆破了,说作者在干什么,还有好水之类的,故作者快马加鞭,敏捷把文章从头更新,将作者的一切运用进程和代码放出来,希望能取得你们的认可,谢谢各位掘友的指正,作者以后会做的更好,感谢你们的支持!