Android使用kotlin实现滑动居中效果
1.自定义CenterLayoutManager
import android.content.Context
import android.util.AttributeSet
import android.util.DisplayMetrics
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView
/**
*@author: njb
*@date: 2023/1/16 23:36
*@desc:
*/
class CenterLayoutManager :LinearLayoutManager{
constructor(context: Context?) : super(context) {}
constructor(
context: Context?,
orientation: Int,
reverseLayout: Boolean
) : super(context, orientation, reverseLayout) {
}
constructor(
context: Context?,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes) {
}
override fun smoothScrollToPosition(
recyclerView: RecyclerView,
state: RecyclerView.State,
position: Int
) {
val smoothScroller: RecyclerView.SmoothScroller = CenterSmoothScroller(recyclerView.context)
smoothScroller.targetPosition = position
startSmoothScroll(smoothScroller)
}
private class CenterSmoothScroller internal constructor(context: Context?) :
LinearSmoothScroller(context) {
override fun calculateDtToFit(
viewStart: Int,
viewEnd: Int,
boxStart: Int,
boxEnd: Int,
snapPreference: Int
): Int {
return boxStart + (boxEnd - boxStart) / 2 - (viewStart + (viewEnd - viewStart) / 2)
}
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float {
return 100f / displayMetrics.densityDpi
}
}
}
2.视频详情适配器:
package com.example.centemanagerdemo.adapter
import android.text.TextUtils
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.centemanagerdemo.R
import com.example.centemanagerdemo.bean.VideoDetailBean
import com.example.centemanagerdemo.utils.TimeUtils
/**
*@author: njb
*@date: 2023/1/16 23:36
*@desc:
*/
class FullVideoDetailAdapter(data:MutableList<VideoDetailBean>):BaseQuickAdapter<VideoDetailBean,BaseViewHolder>(
R.layout.item_full_video_column,data){
override fun convert(helper: BaseViewHolder, item: VideoDetailBean) {
item.let {
val clFullVideo: ConstraintLayout = helper.getView(R.id.cl_full_video)
val ivStart: ImageView = helper.getView(R.id.iv_full_play)
val tvTime: TextView = helper.getView(R.id.tv_full_time)
val tvContent: TextView = helper.getView(R.id.tv_full_content)
if (!TextUtils.isEmpty(item.point.toString())) {
tvTime.setText(TimeUtils.formatVideoTime(item.point))
}
tvContent.text = item.title
addChildClickViewIds(R.id.cl_full_video,R.id.iv_full_play)
if (item.isSelected) {
ivStart.setImageResource(R.mipmap.icon_video_playing)
tvTime.setTextColor(context.getColor(R.color.color_ffc10a))
tvContent.setTextColor(context.getColor(R.color.color_ffc10a))
clFullVideo.setBackgroundResource(R.drawable.shape_video_column_selected_bg)
} else {
ivStart.setImageResource(R.mipmap.icon_video_play)
tvTime.setTextColor(context.getColor(R.color.color_white))
tvContent.setTextColor(context.getColor(R.color.color_white))
clFullVideo.setBackgroundResource(R.drawable.shape_full_video_bg)
}
}
}
}
3.视频详情实体类:
import java.io.Serializable
/**
*@author: njb
*@date: 2023/2/6 16:41
*@desc:
*/
data class VideoDetailBean(
var id:Int = 0,
var title:String = "",
var point:Int = 0,
var url:String = "",
var isSelected:Boolean=false
):Serializable
4.自定义SpacesItemDecoration:
package com.example.centemanagerdemo.decoration;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.view.View;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
/**
* 作者: njb
* 时间: 2021/11/18 0008-上午 10:39
* 描述:
* 来源:
*/
public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private SpacesItemDecorationEntrust mEntrust;
private int mColor;
private int leftRight;
private int topBottom;
public SpacesItemDecoration(int leftRight, int topBottom) {
this.leftRight = leftRight;
this.topBottom = topBottom;
}
public SpacesItemDecoration(int leftRight, int topBottom, int mColor) {
this(leftRight, topBottom);
this.mColor = mColor;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mEntrust == null) {
mEntrust = getEntrust(parent.getLayoutManager());
}
mEntrust.onDraw(c, parent, state);
super.onDraw(c, parent, state);
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (mEntrust == null) {
mEntrust = getEntrust(parent.getLayoutManager());
}
mEntrust.getItemOffsets(outRect, view, parent, state);
}
private SpacesItemDecorationEntrust getEntrust(RecyclerView.LayoutManager manager) {
SpacesItemDecorationEntrust entrust = null;
//要注意这边的GridLayoutManager是继承LinearLayoutManager,所以要先判断GridLayoutManager
if (manager instanceof GridLayoutManager) {
entrust = new GridEntrust(leftRight, topBottom, mColor);
} else if (manager instanceof StaggeredGridLayoutManager) {
entrust = new StaggeredGridEntrust(leftRight, topBottom, mColor);
} else {//其他的都当做Linear来进行计算
entrust = new LinearEntrust(leftRight, topBottom, mColor);
}
return entrust;
}
}
5.MainActiivty代码:
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import com.example.centemanagerdemo.adapter.FullVideoDetailAdapter
import com.example.centemanagerdemo.bean.VideoDetailBean
import com.example.centemanagerdemo.decoration.SpacesItemDecoration
import com.example.centemanagerdemo.manager.CenterLayoutManager
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private var centerAdapter: FullVideoDetailAdapter? = null
private var dataList: MutableList<VideoDetailBean>? = null
private var centerLayoutManager: CenterLayoutManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initAdapter()
}
private fun initAdapter() {
dataList = mutableListOf()
for (i in 0..20) {
val detailModel = VideoDetailBean()
detailModel.title = ("S1 与 Vision+ S1 App 的连接S1")
detailModel.point = (90)
dataList?.add(detailModel)
}
centerAdapter = FullVideoDetailAdapter(dataList!!)
centerLayoutManager = CenterLayoutManager(this)
rv_video.layoutManager = centerLayoutManager
rv_video.addItemDecoration(SpacesItemDecoration(0, 20))
rv_video.adapter = centerAdapter
centerAdapter?.setOnItemChildClickListener { adapter, view, position ->
val list: MutableList<VideoDetailBean> = adapter.data as MutableList<VideoDetailBean>
for (videoDetailModel in list) {
videoDetailModel.isSelected = false
}
list[position].isSelected = true
centerAdapter?.notifyDataSetChanged()
if (view.id == R.id.iv_full_play || view.id == R.id.cl_full_video) {
if (dataList != null && dataList?.size!! > 3) {
centerLayoutManager!!.smoothScrollToPosition(
rv_video,
RecyclerView.State(),
position
)
}
}
}
}
}
6.布局文件代码:
activity_main和item_full_video_cloumn
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_video"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
tools:listitem="@layout/item_full_video_column"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"
android:id="@+id/cl_full_video"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:focusable="true"
android:background="@drawable/shape_full_video_bg"
tools:ignore="ResourceName,MissingConstraints">
<ImageView
android:id="@+id/iv_full_play"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@mipmap/icon_video_play"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_full_time"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="11dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/color_white"
android:textSize="12sp"
app:layout_constraintLeft_toRightOf="@+id/iv_full_play"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:text="01:19" />
<TextView
android:id="@+id/tv_full_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:ellipsize="end"
android:gravity="center|left"
android:textColor="@color/color_white"
android:textSize="12sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/iv_full_play"
android:text="S1 与 Vision+ S1 App 的连接S1 与 Vision+ S1 App 的连接S1 与 Vision+ S1 App 的连接S1 与 Vision+ S1 App 的连接S1 与 Vision+ S1 App 的连接S1 与 Vision+ S1 App 的连接"
tools:ignore="RtlHardcoded" />
</androidx.constraintlayout.widget.ConstraintLayout>