先上效果图:
首先这个界面背景透明,所以我们肯定需要在一个弹窗中嵌套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:
注意,在父布局和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 } }