先上效果图:
首先这个界面背景透明,所以我们肯定需要在一个弹窗中嵌套ViewPager进行操作,先自定义一个DialogFragment:
class TestDialogFragment : DialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return LayoutInflater.from(context).inflate(R.layout.layout_test, container, false)
}
fun show(manager: FragmentManager?) {
show(manager, this::class.java.simpleName)
}
companion object {
fun newInstance(): TestDialogFragment {
return TestDialogFragment()
}
}
}
然后我们确定页面布局,上方是一个ViewPager,下方是一个指示栏加上一个关闭按钮,并且ViewPager与指示栏有部分重合,为了快速实现指示栏效果,我使用了开源项目MagicIndicator:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:orientation="vertical">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="@dimen/dp_100"
android:background="@color/color_ff3a455e"
android:orientation="horizontal"
android:layout_alignParentBottom="true">
<net.lucode.hackware.magicindicator.MagicIndicator
android:id="@+id/reportDetailIndicator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/dp_16"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ivClose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/dp_16"
android:src="@drawable/ic_delete" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.viewpager.widget.ViewPager
android:id="@+id/reportDetailViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
android:layout_marginBottom="@dimen/dp_60"
android:layout_weight="1"
android:clipChildren="false" />
</RelativeLayout>
注意,在父布局和ViewPager中要加上clipChildren=“false”,该属性表示当子view超出限制时是否切割,默认为true
然后我们在DialogFragment的onViewCreated方法中初始化控件:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initView(view)
}
private fun initView(view: View?) {
view?.apply {
//初始化magicIndicator
val commonNavigator = CommonNavigator(activity)
//设置缓存三页
reportDetailViewPager.offscreenPageLimit = 3
//设置页面之间的间隔,这里的效果需要重合,所以我们设置为-200
reportDetailViewPager.pageMargin = -200
reportDetailViewPager.adapter = object : FragmentStatePagerAdapter(childFragmentManager) {
override fun getItem(p0: Int): Fragment {
return list[p0]
}
override fun getCount(): Int {
return list.size
}
}
initIndicator(commonNavigator, this)
}
}
private fun initIndicator(commonNavigator: CommonNavigator, view: View?) {
view?.apply {
//设置滑动
commonNavigator.scrollPivotX = 0.65f
//设置指示器adapter
commonNavigator.adapter = object : CommonNavigatorAdapter() {
override fun getTitleView(context: Context, index: Int): IPagerTitleView {
val simpleTitleView = TestTitleView(context)
//设置指示器内容
with(simpleTitleView) {
isSingleLine = false
normalColor = ContextCompat.getColor(context, R.color.color_d7d7d9)
selectedColor = ContextCompat.getColor(context, R.color.white)
selectedSize = 14f
normalSize = 12f
text = "2019/2/2 \n 2:22"
gravity = Gravity.CENTER
setOnClickListener { [email protected] = index }
return this
}
}
//暂定数据源为5页
override fun getCount(): Int {
return 5
}
override fun getIndicator(context: Context?): IPagerIndicator? {
return null
}
}
reportDetailIndicator.navigator = commonNavigator
//绑定ViewPager
ViewPagerHelper.bind(reportDetailIndicator, reportDetailViewPager)
ivClose.setOnClickListener {
dialog.dismiss()
}
}
}
这里我们看到ViewPager是有不同大小的,前一页和后一页都要比当前页小一点,所以我们新建一个DepthPageTransformer继承自ViewPager的PageTransformer:
class DepthPageTransformer : ViewPager.PageTransformer {
//透明度和高度最小值
private val MAX_SCALE = 0.90f
private val MIN_SCALE = 0.70f
private val MIN_ALPHA = 0.3f
override fun transformPage(page: View, position: Float) {
val width = page.width
if (position < -1) {
page.alpha = MIN_ALPHA
page.scaleY = MIN_SCALE
page.scaleX = MIN_SCALE
} else if (position <= 1) {
if (position == 0f) { //当前页面
page.alpha = 1.0f
page.scaleY = MAX_SCALE
page.scaleX = MAX_SCALE
} else {
if (position < 0) {
//平滑变化
val f = MIN_ALPHA + (1 - MIN_ALPHA) * (1 + position)
page.alpha = f
val s = MIN_SCALE + (MAX_SCALE - MIN_SCALE) * (1 + position)
page.scaleY = s
page.scaleX = s
} else {
//平滑变化
val f = MIN_ALPHA + (1 - MIN_ALPHA) * (1 - position)
page.alpha = f
val s = MIN_SCALE + (MAX_SCALE - MIN_SCALE) * (1 - position)
page.scaleY = s
page.scaleX = s
}
}
}
}
嗯,现在我们加入数据源:
val list by lazy {
listOf(TestFragment(), TestFragment(), TestFragment(), TestFragment(), TestFragment())
}
设置ViewPager的Adapter:
reportDetailViewPager.adapter = object : FragmentStatePagerAdapter(childFragmentManager) {
override fun getItem(p0: Int): Fragment {
return list[p0]
}
override fun getCount(): Int {
return list.size
}
}
然后设置PageTransformer:
reportDetailViewPager.setPageTransformer(true, DepthPageTransformer())
重写show方法:
fun show(manager: FragmentManager?) {
show(manager, this::class.java.simpleName)
}
然后调用
TestDialogFragment.newInstance().show(fragmentManager);
运行代码,发现效果与我们的不同,背景是白色,并且大小不正常,那么我们再在dialogFragment中重新设置一下大小与背景:
override fun onStart() {
super.onStart()
val window = dialog.window
val windowParams = window!!.attributes
window.setLayout(-1, -2) //高度自适应,宽度全屏
windowParams.gravity = Gravity.CENTER //在顶部显示
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)//设置背景透明
window.attributes = windowParams
}
全部代码:
class TestDialogFragment : DialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return LayoutInflater.from(context).inflate(R.layout.layout_test, container, false)
}
fun show(manager: FragmentManager?) {
show(manager, this::class.java.simpleName)
}
override fun onStart() {
super.onStart()
val window = dialog.window
val windowParams = window!!.attributes
window.setLayout(-1, -2) //高度自适应,宽度全屏
windowParams.gravity = Gravity.CENTER //在顶部显示
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
window.attributes = windowParams
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initView(view)
}
val list by lazy {
listOf(ApprovalFragment(), ApprovalFragment(), ApprovalFragment(), ApprovalFragment(), ApprovalFragment())
}
private fun initView(view: View?) {
view?.apply {
val commonNavigator = CommonNavigator(activity)
reportDetailViewPager.setPageTransformer(true, DepthPageTransformer())
reportDetailViewPager.offscreenPageLimit = 3
reportDetailViewPager.pageMargin = -200
reportDetailViewPager.adapter = object : FragmentStatePagerAdapter(childFragmentManager) {
override fun getItem(p0: Int): Fragment {
return list[p0]
}
override fun getCount(): Int {
return list.size
}
}
initIndicator(commonNavigator, this)
}
}
private fun initIndicator(commonNavigator: CommonNavigator, view: View?) {
view?.apply {
commonNavigator.scrollPivotX = 0.65f
commonNavigator.adapter = object : CommonNavigatorAdapter() {
override fun getTitleView(context: Context, index: Int): IPagerTitleView {
val simpleTitleView = TaskDetailTabTitleView(context)
with(simpleTitleView) {
isSingleLine = false
normalColor = ContextCompat.getColor(context, R.color.color_d7d7d9)
selectedColor = ContextCompat.getColor(context, R.color.white)
selectedSize = 14f
normalSize = 12f
text = "2019/2/2 \n 2:22"
gravity = Gravity.CENTER
setOnClickListener { [email protected] = index }
return this
}
}
override fun getCount(): Int {
return 5
}
override fun getIndicator(context: Context?): IPagerIndicator? {
return null
}
}
reportDetailIndicator.navigator = commonNavigator
//绑定ViewPager
ViewPagerHelper.bind(reportDetailIndicator, reportDetailViewPager)
ivClose.setOnClickListener {
dialog.dismiss()
}
}
}
companion object {
fun newInstance(): TestDialogFragment {
return TaskReportDetailDialogFragment()
}
}
class DepthPageTransformer : ViewPager.PageTransformer {
//透明度和高度最小值
private val MAX_SCALE = 0.90f
private val MIN_SCALE = 0.70f
private val MIN_ALPHA = 0.3f
override fun transformPage(page: View, position: Float) {
val width = page.width
if (position < -1) {
page.alpha = MIN_ALPHA
page.scaleY = MIN_SCALE
page.scaleX = MIN_SCALE
} else if (position <= 1) {
if (position == 0f) { //当前页面
page.alpha = 1.0f
page.scaleY = MAX_SCALE
page.scaleX = MAX_SCALE
} else {
if (position < 0) {
//平滑变化
val f = MIN_ALPHA + (1 - MIN_ALPHA) * (1 + position)
page.alpha = f
val s = MIN_SCALE + (MAX_SCALE - MIN_SCALE) * (1 + position)
page.scaleY = s
page.scaleX = s
} else {
//平滑变化
val f = MIN_ALPHA + (1 - MIN_ALPHA) * (1 - position)
page.alpha = f
val s = MIN_SCALE + (MAX_SCALE - MIN_SCALE) * (1 - position)
page.scaleY = s
page.scaleX = s
}
}
}
}
}
}
TestTitleView:
class TaskDetailTabTitleView(context: Context) : SimplePagerTitleView(context) {
var selectedSize = 18f
var normalSize = 14f
override fun onSelected(index: Int, totalCount: Int) {
super.onSelected(index, totalCount)
textSize = selectedSize
}
override fun onDeselected(index: Int, totalCount: Int) {
super.onDeselected(index, totalCount)
textSize = normalSize
}
}