上接上一篇文章,继续介绍这个库的使用。
- 使用NavigationView来实现抽屉菜单界面
上次也说了,我们费劲用Toolbar实现的抽屉式菜单,这不是又有一个封装好的组件吗,都是封装带师。废话不多说,做好就这样:
- 首先,我们在上一篇文章的基础上进行改造,修改主界面的布局文件main_activity.xml。
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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"
android:fitsSystemWindows="true"
android:id="@+id/draw_layout"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:id="@+id/layout_out"
android:orientation="vertical"
>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorColor="#ADBE107E"
app:tabMode="scrollable"
/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/navigation_header"
app:menu="@menu/draw_mean"
/>
</androidx.drawerlayout.widget.DrawerLayout>
- 然后,创建要放入NavigationView的界面,navigation_header.xml。那个image01是我的图片资源。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="?attr/colorPrimaryDark"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
>
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="50dp"
android:background="@mipmap/image01"
android:scaleType="centerCrop"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:text="穹我此生-皆无悔恨"
android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionMode.Title"
android:textSize="20sp"
/>
</LinearLayout>
- 修改主活动的代码
import android.app.Activity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.LinearLayout
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.viewpager.widget.ViewPager
import com.google.android.material.navigation.NavigationView
import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout
class MainActivity :AppCompatActivity() {
var mDrawerLayout:DrawerLayout? = null
var mViewPager:ViewPager? = null
var mTabLayout:TabLayout? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
initViewPager()
}
fun initViewPager(){
mTabLayout = findViewById(R.id.tab_layout)
mViewPager = findViewById(R.id.view_pager)
val titles = ArrayList<String>()
val fragments= ArrayList<Fragment>()
titles.add("精选")
titles.add("体育")
titles.add("巴萨")
titles.add("购物")
titles.add("明星")
titles.add("精选")
titles.add("体育")
titles.add("巴萨")
titles.add("购物")
titles.add("明星")
//初始化tab与fragment
titles.forEach { mTabLayout!!.addTab(mTabLayout!!.newTab().setText(it)); fragments.add(ListFragment()) }
val mFragmentAdapter:FragmentAdapter = FragmentAdapter(this.supportFragmentManager, fragments, titles)
mViewPager!!.adapter = mFragmentAdapter
mTabLayout!!.setupWithViewPager(mViewPager)
mTabLayout!!.setTabsFromPagerAdapter(mFragmentAdapter)
//在这里设置新的抽屉界面
val navigationView:NavigationView = findViewById(R.id.navigation_view)
mDrawerLayout = findViewById(R.id.draw_layout)
navigationView!!.setNavigationItemSelectedListener {
it.setChecked(true)
val title:String = it.title.toString()
Toast.makeText(applicationContext, title, Toast.LENGTH_SHORT).show()
mDrawerLayout!!.closeDrawers()
true
}
}
}
这就OK啦。
- 使用CoordinatorLayout来实现ToolBar的隐藏和折叠
像大多数的APP,我们在向上滑动的时候,上面的toolbar都会进行折叠,目的是带来更加宽阔的视野。可以方便地采用CoordinatorLayout来实现,这个效果。
- 首先,修改我们的主页面main_activity.xml。
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:fitsSystemWindows="true"
android:id="@+id/coordinator_layout"
tools:context=".MainActivity"
>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorColor="#ADBE107E"
app:tabMode="scrollable"
/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:clickable="true"
android:onClick="checkin"
android:src="@drawable/abc_vector_test"
app:layout_anchor="@id/view_pager"
app:layout_anchorGravity="bottom|right|end"
/>
<!--特别注意, layout_anchor的指向,不能指向父布局,否则,会报错-->
</androidx.coordinatorlayout.widget.CoordinatorLayout>
放入了,一个浮动的按钮。
- 然后,修改一点主活动代码MainActivity.kt。
import android.app.ActionBar
import android.app.Activity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.LinearLayout
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.viewpager.widget.ViewPager
import com.google.android.material.navigation.NavigationView
import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout
class MainActivity :AppCompatActivity() {
var mViewPager:ViewPager? = null
var mTabLayout:TabLayout? = null
var mToolbar:Toolbar? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
initViewPager()
}
fun initViewPager(){
//这里改了一点
mToolbar = findViewById(R.id.toolbar)
setSupportActionBar(mToolbar)
val ab:androidx.appcompat.app.ActionBar = supportActionBar!!
ab.setDisplayHomeAsUpEnabled(true)
mTabLayout = findViewById(R.id.tab_layout)
mViewPager = findViewById(R.id.view_pager)
val titles = ArrayList<String>()
val fragments= ArrayList<Fragment>()
titles.add("精选")
titles.add("体育")
titles.add("巴萨")
titles.add("购物")
titles.add("明星")
titles.add("精选")
titles.add("体育")
titles.add("巴萨")
titles.add("购物")
titles.add("明星")
//初始化tab与fragment
titles.forEach { mTabLayout!!.addTab(mTabLayout!!.newTab().setText(it)); fragments.add(ListFragment()) }
val mFragmentAdapter:FragmentAdapter = FragmentAdapter(this.supportFragmentManager, fragments, titles)
mViewPager!!.adapter = mFragmentAdapter
mTabLayout!!.setupWithViewPager(mViewPager)
mTabLayout!!.setTabsFromPagerAdapter(mFragmentAdapter)
}
//点击浮动按钮触发
fun checkin(view:View):Unit{
Snackbar.make(view, "点击", Snackbar.LENGTH_SHORT)
.setAction("评论", View.OnClickListener { })
.setDuration(BaseTransientBottomBar.LENGTH_SHORT)
.show()
}
}
滑动效果:
- 那么,我想不仅仅折叠Toolbar,我还想,把其它组件连同它一起折叠了呢?这个时候,就需要用到CollapsingToolbarLayout布局了。
这个组件,会将自己包裹的组件(包括Toolbar)一起进行滑动时的折叠.
- 首先,修改主布局文件main_activity.xml文件。
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:fitsSystemWindows="true"
android:id="@+id/coordinator_layout"
tools:context=".MainActivity"
>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/collapsing_toolbar"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="@mipmap/image01"
/>
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabIndicatorColor="#ADBE107E"
app:tabMode="scrollable"
/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:clickable="true"
android:onClick="checkin"
android:src="@drawable/abc_vector_test"
app:layout_anchor="@id/view_pager"
app:layout_anchorGravity="bottom|right|end"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
加入ScollapsingToolbarLayout布局。
- 然后,修改主活动,设定一下标题
val collapsingToolbar:CollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar)
collapsingToolbar.title = "春日野穹"
- 最后,修改一下RecyclerView的布局。就是ListFragment.kt
val mRecyclerView = contentView.findViewById<RecyclerView>(R.id.list)
mRecyclerView.layoutManager = StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL)
mRecyclerView.itemAnimator = DefaultItemAnimator()
效果如下:
滑上去后:
- 其实上面那个效果,也是封装出来的,毕竟封装带师。下面,就说一说行为的定义吧。自定义Behavior也有用到,也就是上面的@string/appbar_scolling_view_behavior。下面实现一个向下滑动底部导航消失,向上滑动出现的行为。
一般来说有两种方式,分别是:
- 定义的View监听CoordinatorLayout里的滑动状态
- 定义的View监听另一个View的状态变化。
第一种
- 创建的行为
package com.example.compant
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewPropertyAnimator
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.ViewCompat
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import java.util.jar.Attributes
class FooterBehavior(val context: Context, val attrs:AttributeSet) : CoordinatorLayout.Behavior<View>(context, attrs){
private var directionChange:Int = 0
/**
*
*/
override fun onStartNestedScroll(
coordinatorLayout: CoordinatorLayout,
child: View,
directTargetChild: View,
target: View,
axes: Int,
type: Int
): Boolean {
return axes and ViewCompat.SCROLL_AXIS_VERTICAL !== 0
}
/**
*
*/
override fun onNestedPreScroll(
coordinatorLayout: CoordinatorLayout,
child: View,
target: View,
dx: Int,
dy: Int,
consumed: IntArray,
type: Int
) {
println(1234)
if(dy > 0 && directionChange < 0 || dy < 0 && directionChange > 0){
child.animate().cancel()
directionChange = 0
}
directionChange += dy
if(directionChange > child.height && child.visibility == View.VISIBLE){
hide(child)
}else if(directionChange < 0 && child.visibility == View.GONE){
show(child)
}else{
}
}
/**
* 隐藏函数
*/
private fun hide(view:View){
val animator:ViewPropertyAnimator = view.animate().translationY(view.height.toFloat())
.setInterpolator(object :FastOutSlowInInterpolator(){})
.setDuration(200)
animator.setListener(object :AnimatorListenerAdapter(){
override fun onAnimationEnd(animation: Animator?) {
view.visibility = View.GONE
}
})
animator.start()
}
/**
* 显示函数
*/
private fun show(view:View):Unit{
val animator:ViewPropertyAnimator = view.animate().translationY(0F)
.setInterpolator(object :FastOutSlowInInterpolator(){})
.setDuration(200)
animator.setListener(object :AnimatorListenerAdapter(){
override fun onAnimationEnd(animation: Animator?) {
view.visibility = View.VISIBLE
}
})
animator.start()
}
}
第二种方式
- 创建行为
package com.example.compant
import android.content.Context
import android.util.AttributeSet
import android.view.View
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.appbar.AppBarLayout
class FooterMyBehavior(val context: Context, val attrs: AttributeSet) : CoordinatorLayout.Behavior<View>(context, attrs){
override fun layoutDependsOn(
parent: CoordinatorLayout,
child: View,
dependency: View
): Boolean {
return dependency::class == AppBarLayout::class
}
override fun onDependentViewChanged(
parent: CoordinatorLayout,
child: View,
dependency: View
): Boolean {
var translatetionY:Float = Math.abs(dependency.y)
child.translationY = translatetionY
return true
}
}
- 把行为设置为app:layout_behavior就可以了。
app:layout_behavior="com.example.compant.FooterMyBehavior"
特别说明,第一种存在问题,应该是Android的库版本问题,这个在低版本里面可以完美实现的行为,而在较高的版本中,会出现只会检测到第一次滑动的Bug。这个是这个版本中RecyclerView和这个组件有冲突导致的结果。