前言
封闭、无聊、刷皮皮、详情页、交互式、有意思、实现下
1、分析功能点
2、实现思绪
那么即可左滑又可右滑还不辩说的东西是什么
ViewPager
好!确定详情页父结构使用Viewpager那么咱们只须要思量下滑手势的题目了
3、实现 (不要在意定名、特殊在意检察项目即可满足好奇心?)
XML
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <merge android:layout_width="match_parent" android:layout_height="match_parent" tools:parentTag=".widget.XBBDetailView"> <!-- 状态栏 --> <com.kasiengao.ksgframe.common.widget.CView android:id="@+id/status_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/black" tools:layout_height="24dp" /> <!-- ViewPager --> <androidx.viewpager.widget.ViewPager android:id="@+id/detail_vp" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/status_bar" androidverScrollMode="never" /> <!-- Back --> <androidx.appcompat.widget.AppCompatImageView android:id="@+id/back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@id/detail_vp" android:layout_marginStart="@dimen/view_space" android:layout_marginTop="12dp" android:elevation="5dp" android:src="@drawable/ic_cover_back" /> </merge></layout>class XBBDetailView(context: Context) : RelativeLayout(context) { private val mBinding: LayoutXbbDetailBinding by lazy { DataBindingUtil.inflate( LayoutInflater.from(context), R.layout.layout_xbb_detail, this, true ) }}- 列表到详情页的过渡动画
皮皮虾仿皮皮虾
看得出来是从列表中的视频容器Y坐标为出发点平移到顶部的一个动画效果
- 获取列表视频容器在屏幕中的坐标getLocationOnScreen
- 拿到列表视频容器的Y到减去状态栏高度位置做一个平移动画即可
- 数据源截取聚集subList从点击列表的position到size做一个截取
// 列表截取val subList = mAdapter.data.subList(position, mAdapter.data.size)/** * 打开详情页 * * @param position 列表位置 * @param data 数据源 * @param listContainer 列表容器 */fun openDetail(position: Int, data: List<VideoBean>, listContainerlayerContainerView{ // 添加到View层级下 this.mActivity.findViewById<ViewGroup>(android.R.id.content)?.let { if (!it.contains(this)) { it.addView(this) } } // 列表容器坐标 val location = IntArray(2) this.mListContainer.getLocationOnScreen(location) // 动画 ObjectAnimator.ofFloat( mBinding.detailVp, Y, location[1].toFloat(), mStatusBarHeight.toFloat() ).let { it.interpolator = LinearInterpolator() it.duration = 150 it.start() } // Init this.post { this.mBinding.detailVp.setCurrentItem(1, false) }}留意:setCurrentItem(1, false)ViewPager初始页肯定要设置为第1页,须要预留第0页作为关闭页
看起来是不是so easy来咱接着往下走
- 右滑切换短视频
这里着实就是简朴的ViewPager右滑切换了
皮皮虾仿皮皮虾
- 但是须要留意的是右滑切换后同时要同步Recycler的Item位置
- 否则findViewHolderForLayoutPosition会报空指针,
- 同步Recycler的Item位置是由于在关闭详情页的也须要做过渡动画
override fun onPageSelected(position: Int) { ... // 同步列表Item的位置 scrollToPositionWithOffset(getRealListPosition())}override fun onPageScrollStateChanged(state: Int) { ... when (state) { ViewPager.SCROLL_STATE_IDLE -> { // 同步列表的容器 mListContainer = getItemPlayContainer(getRealListPosition()) } } }}/** * 指定Item滑动到顶部 */fun scrollToPositionWithOffset(position: Int) { (layoutManager as LinearLayoutManager).scrollToPositionWithOffset(position, 0)}/** * 获取Item中的视频容器View */fun getItemPlayContainer(position: Int): PlayerContainerView { return (findViewHolderForLayoutPosition(position) as XBBAdapter.ViewHolder).mPlayContainer}- 左滑关闭详情页
皮皮虾仿皮皮虾在上面咱们说到了预留了第0页作为了关闭页,那么很简朴第0页只须要添加一个空View且透明即可,在滑动结束后关闭详情页即可。
override fun onPageSelected(position: Int) { // 关闭页 if (position == PAGE_FINISH) { ... // 切回至旧容器 (原列表容器) mSignalPlayer.bindContainer(mListContainer, false) return }}override fun onPageScrollStateChanged(state: Int) { when (state) { ViewPager.SCROLL_STATE_IDLE -> { ... // 关闭页 if (currentItem == PAGE_FINISH) { // Finish finishDetail() return } } }}/** * 关闭详情页 */private fun finishDetail() { // 从View层级中移除 this.mActivity.findViewById<ViewGroup>(android.R.id.content) ?.removeView(this@XBBDetailView) ...}左滑关闭逻辑也就结束了、也好坏常的easy哈?
- 下滑关闭详情页
皮皮虾仿皮皮虾
这里就比力关键了须要用到变乱分发
起首在详情页可以看到品评列表可上下滑动,那就须要限制在列表顶部的时间才可以下滑关闭
这里须要在父结构中重写onInterceptTouchEvent去判断滑动偏移量与列表是否在顶部逻辑
/** * 变乱分发 */override fun onInterceptTouchEvent(event: MotionEvent): Boolean { var intercept = false when (event.action) { MotionEvent.ACTION_DOWN -> { this.mDownX = event.x this.mDownY = event.y } MotionEvent.ACTION_MOVE -> { if ((event.y - mDownY) > 23) { if (mItemView.getScrollView().isOnTop) { intercept = true } } } } return intercept}然后重写onTouchEvent当变乱被拦截时此处会被实行,然后根据 X Y 坐标去设置更新容器即可
override fun onTouchEvent(event: MotionEvent): Boolean { if (!mItemView.getScrollView().isOnTop) { return true } when (event.action) { MotionEvent.ACTION_DOWN -> { this.mDownX = event.x this.mDownY = event.y } MotionEvent.ACTION_UP -> { ... } MotionEvent.ACTION_MOVE -> { val moveX = event.x - mDownX this.mMoveY = (event.y - mDownY) this.mItemView.getPlayerContainer().x = moveX this.mItemView.getPlayerContainer().y = mMoveY ... } } return true}到这里就结束了效果也实现了。
在这里也只是提供个思绪有更好的办法欢迎品评区一起讨论,那下面就直接堆栈地点了感爱好的朋侪么渴望给个Star支持一下?
KsgFrame |