一个用KT写的播放器上层UI框架(1)

265 阅读7分钟

播放器主view

IeltsMediaPlayer.kt

class IeltsMediaPlayer (context: Context, attrs: AttributeSet? = null) : BaseWidget(context,attrs){
    /**
     * 视频播放器view
     */
    var playerView:KoolVideoView?=null

    /**
     * 所有视频上层UI的父类,需要时add进去
     */
    var controlParent:ControllerView?=null

    /**
     * 返回按钮
     */
    var mBackArrow: ImageView?=null

    /**
     * 配置类,所有外界传出的东西通过此配置拿到
     */
    var mPlayerConfig:PlayerConfig?=null
    //---------下面是所有视频上显示的视图-start
    private var vScreenController:VScreenController?=null
    private var hScreenController:HScreenController?=null
    private var loading:PlayerLoadingView?=null
    private var seekMonitor:SeekingMonitorView?=null
    private var volumn:GestureVolumn?=null
    private var brightness:GestureBrightness?=null
    private var netError:PlayerNetErrorView?=null
    private var complete:PlayCompleteView?=null
    //---------下面是所有视频上显示的视图-end
    var matchRLParams:RelativeLayout.LayoutParams?=null
    var matchRLParamsChild:RelativeLayout.LayoutParams?=null
    var matchRLHWrapParams:RelativeLayout.LayoutParams?=null
    var matchFLParams:RelativeLayout.LayoutParams?=null
    //配置
    private var mLogLevel: Int = 2
    //真实屏幕尺寸
    private var mRealWidth:Int=0
    private var mRealHeight:Int=0

    //-----------标志位 start
    private var isFullScreen:Boolean=false
    //标识 是否有横向或者竖向的控制view正在显示
    private var isScreenControlShowing:Boolean=false

    /**
     * 标志 当前正在展示的view类型
     * 对应的是上面的这几个view
     */
    private var showViewType:ShowViewType = ShowViewType.Empty
    private var isPause:Boolean=false
    //-----------标志位 end

    //定时器 Disposable,用于更新播放器进度
    var disposable: Disposable?=null

    //重新播放回调
    var replay:()->Unit={}
    //播放下一个回调
    var playNext:()->Unit={}

    //上传进度到服务器
    var uploadProgress:()->Unit={}

    //初始化进度开始时间
    var initProgress:()->Unit={}

    //3s自动小时handler
    var dismissHandler= Handler()

    var runnable:Runnable= Runnable {
        if (isScreenControlShowing){
            removeAllChildView()
        }
    }
    override fun initView() {
        //初始化后面用的到的params
        matchRLParams=RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT)
        matchRLParams?.centerInParent()
        matchRLParamsChild=RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT)
        matchRLParamsChild?.centerInParent()
        matchRLHWrapParams=RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.WRAP_CONTENT)
        matchFLParams=RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT)
        //初始化控件
        playerView = view?.findViewById(R.id.playerView)
        controlParent=view?.findViewById(R.id.controlParent)
        mBackArrow=view?.findViewById(R.id.mBackArrow)


        //初始化竖屏控制区域
        vScreenController= VScreenController(context,null)
        vScreenController?.layoutParams=matchRLParamsChild
        vScreenController?.toFullScreen={
            ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE.also { (context as AbsPlayerActivity?)?.requestedOrientation = it }
            toFullScreen()
            ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED.also { (context as AbsPlayerActivity?)?.requestedOrientation = it }
        }
        vScreenController?.pauseOrPlayClick={
            if(playerView?.isPlaying ==true){
                pauseVideo()
            }else{
                startVideo()
            }

        }
        vScreenController?.seekTo={
            playerView?.seekTo(it)
        }
        //初始化横屏控制区域
        hScreenController= HScreenController(context,null)
        hScreenController?.layoutParams=matchRLParamsChild
        hScreenController?.toHalfScreen={
            ActivityInfo.SCREEN_ORIENTATION_PORTRAIT.also { (context as AbsPlayerActivity?)?.requestedOrientation = it }
            toHalfScreen()
            ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED.also { (context as AbsPlayerActivity?)?.requestedOrientation = it }
        }
        hScreenController?.pauseOrPlayClick={
            if(playerView?.isPlaying ==true){
                pauseVideo()
            }else{
                startVideo()
            }

        }
        hScreenController?.seekTo={
            playerView?.seekTo(it)
        }
        //初始化网络错误
        netError = PlayerNetErrorView(context,null)
        netError?.layoutParams=matchRLParamsChild
        //初始化进度监听view
        seekMonitor = SeekingMonitorView(context,null)
        seekMonitor?.layoutParams=matchRLParamsChild
        seekMonitor?.seekTo={
            playerView?.seekTo(it)
        }
        //初始化loading View
        loading = PlayerLoadingView(context,null)
        loading?.layoutParams=matchRLParamsChild
        //初始化调整声音的view
        volumn = GestureVolumn(context)
        volumn?.layoutParams=matchRLParamsChild
        //初始化调整亮度的view
        brightness = GestureBrightness(context)
        brightness?.layoutParams=matchRLParamsChild
        //初始化 播放完成的view
        complete = PlayCompleteView(context)
        complete?.layoutParams=matchRLParamsChild
        complete?.replay={
            replay()
        }
        complete?.playNext={
            playerView?.pause()
            playNext()
        }
    }

    override fun initInnerEvent() {
        mBackArrow?.setOnClickListener {
            v->
            mPlayerConfig?.mActivity?.finish()
        }
        controlParent?.setGestureListener(object:ControllerView.OnControlEventListener{
            override fun onTap(i: Int) {
                //如果当前展示v or h 屏幕控制view中则点击移除
                if(isScreenControlShowing){
                    removeAllChildView()
                }else{
                    //如果当前展示为空时点击重建新的h or v 控制view
                    if(showViewType==ShowViewType.Empty){
                        removeAllChildView()
                        isScreenControlShowing=true
                        showControlView()
                    }
                }

            }

            override fun onTouchMove(direction: Int, movedX: Float, movedY: Float) {
                if (direction == ControllerView.OnControlEventListener.REGION_LEFT) {
                    adjustBrightness(movedY)
                } else if (direction == ControllerView.OnControlEventListener.REGION_RIGHT) {
                    adjustVolumn(movedY)
                } else if (direction == ControllerView.OnControlEventListener.REGION_CENTER) {
                    adjustSeekStart(movedX)
                }
            }

            override fun onTouchUp(i: Int) {
                if(showViewType==ShowViewType.SeekMonitorView){
                    seekMonitor?.adjustSeekEnd()
                }
                removeAllChildView()
            }
        })

        disposable = Observable.interval(0, 1, TimeUnit.SECONDS)
            .subscribeOn(AndroidSchedulers.mainThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe {
                if(!isPause){
                    //更新当前正在播放时间
                    vScreenController?.updateProgress(playerView?.currentPosition?:0)
                    hScreenController?.updateProgress(playerView?.currentPosition?:0)
                }
            }
    }

    override fun getLayoutId()= R.layout.view_ielts_player

    fun getMediaPlayerControl()=playerView

    fun initPlayerConfig(playerConfig: PlayerConfig){
        this.mPlayerConfig=playerConfig
        getRealScreenWidth()
        initVideoView()
    }

    /**
     * 移除controlParent中所有子view的方法,切记在做与 isScreenControlShowing
     * 和showType相关处理的时候记得要先执行此方法,否则会出现程序执行顺序异常
     */
    private fun removeAllChildView(){
        isScreenControlShowing=false
        showViewType = ShowViewType.Empty
        controlParent?.removeAllViews()
    }

    private fun initVideoView() {
        if (playerView != null) {
            playerView?.setToken(mPlayerConfig?.mToken)
            playerView?.setCacheEnable(true)
            playerView?.setCacheDir(getCacheDir())
            playerView?.setOnBufferingUpdateListener(mOnBufferingUpdateListener)
            playerView?.setOnCompletionListener(mOnCompletionListener)
            playerView?.setOnErrorListener(mOnErrorListener)
            playerView?.setOnPreparedListener(mOnPreparedListener)
            playerView?.setOnInfoListener(mOnInfoListener)
            playerView?.enableBackgroundPlay(true)
        }
        toHalfScreen()
    }

    fun setCacheDir(cacheDir: String?) {
        if (playerView != null) {
            playerView?.setCacheDir(cacheDir)
        }
    }

    /**
     * 初始化视频为竖屏
     */
    fun toHalfScreen(){
        val halfLayoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
            mPlayerConfig?.mActivity?.resources?.getDimensionPixelSize(R.dimen.player_height)?:RelativeLayout.LayoutParams.WRAP_CONTENT
        )
        this.playerView?.layoutParams = halfLayoutParams
        this.controlParent?.layoutParams = halfLayoutParams
        //设置当前容器控件半屏
        layoutParams=matchRLHWrapParams
    }

    private fun toFullScreen(){
        val params1 = if (mRealHeight/mRealWidth.toFloat() <= 16.toFloat() / 9) {
            // 屏幕宽高比 <= 16:9
            RelativeLayout.LayoutParams(mRealHeight, mRealHeight * 9 / 16)
        } else {
            RelativeLayout.LayoutParams(mRealWidth * 16 / 9, mRealWidth)
        }
        params1.centerInParent()
        this.playerView?.layoutParams = params1
        this.controlParent?.layoutParams = params1
        //设置当前容器控件全屏
        layoutParams=matchRLParams
    }

    /**
     * 获取屏幕真实宽高
     */
    fun getRealScreenWidth() {
        val display = mPlayerConfig?.mActivity?.windowManager?.getDefaultDisplay()
        val realMetrics = DisplayMetrics()
        display?.getRealMetrics(realMetrics)
        mRealWidth = realMetrics.widthPixels
        mRealHeight = realMetrics.heightPixels
    }

    /**
     * ------------------------------------ activity related end -------------------------------------------------
     */
    /**
     * 播放
     */
    fun play(uri: Uri?, titleName: String, showController: Boolean) {
//        currentTitle = titleName
        playerView?.setVideoURI(uri)
        hScreenController?.setTitle(titleName)
        showLoadingView()
        loading?.showPreLoading()
    }

    /**
     * ------------------------------------ initial player event listener start -------------------------------------------------
     */
    private val mOnPreparedListener =
        IMediaPlayer.OnPreparedListener { mp ->
            var duration = getMediaPlayerControl()?.duration?:0
            vScreenController?.setTotalTime(duration)
            hScreenController?.setTotalTime(duration)
            mPlayerConfig?.mediaPlayListener?.mPrepared(mp)
            vScreenController?.showPlaying()
            hScreenController?.showPlaying()
            //当前显示加载中的话则移除
            if(showViewType==ShowViewType.LoadingView){
                removeAllChildView()
            }
        }

    private val mOnBufferingUpdateListener =
        IMediaPlayer.OnBufferingUpdateListener { mp, percent -> }

    private val mOnInfoListener =
        IMediaPlayer.OnInfoListener { mp, what, extra ->
            mPlayerConfig?.mediaPlayListener?.mInfo(mp, what, extra)
            when (what) {
                KoolMediaPlayer.MEDIA_INFO_NETWORK_BANDWIDTH -> {
                    if(showViewType==ShowViewType.LoadingView){
                        loading?.updateLoadingSpeed(what,extra)
                    }
                }
                KoolMediaPlayer.MEDIA_INFO_BUFFERING_START -> {
                    if(showViewType!=ShowViewType.LoadingView){
                        showLoadingView()
                    }
                    loading?.showBuffering()
                }
                KoolMediaPlayer.MEDIA_INFO_BUFFERING_END -> {
                    if(showViewType==ShowViewType.LoadingView){
                        removeAllChildView()
                    }

                }
                KoolMediaPlayer.MEDIA_INFO_NETWORK_CACHE_BUFFING -> {
                    if(isFullScreen){
                        hScreenController?.updateSecondCache(extra)
                    }else{
                        hScreenController?.updateSecondCache(extra)
                    }
                }
                KoolMediaPlayer.MEDIA_INFO_BUFFERING_TIMEOUT, KoolMediaPlayer.MEDIA_INFO_BUFFERING_MAXFREQ ->
                {
                    Log.i("--->","b")
                    showNetErrorView()
                }
                else -> {
                }
            }
            false
        }

    private val mOnCompletionListener =
        IMediaPlayer.OnCompletionListener { mp ->
            //播放中断网会奇怪的走播放完成回调,故在此做相应的判断处理
            if (NetworkUtil.isNetAvailable(context)) {
                mPlayerConfig?.mediaPlayListener?.mCompletion(mp)
                vScreenController?.showPlayEnd()
                hScreenController?.showPlayEnd()
                showPlayCompleteView()
            } else { //需要先暂停,否则进度条会自动走到百分之百。
                pauseVideo()
                Log.i("--->","a")
                showNetErrorView()
            }
        }

    private val mOnErrorListener =
        IMediaPlayer.OnErrorListener { iMediaPlayer, what, extra, tips ->
            val errorEvent = mPlayerConfig?.mediaPlayListener?.mError(iMediaPlayer, what, extra, tips)
            if (errorEvent != null) {
                BaseApplication.toast(errorEvent.errorText)
            } else {
                BaseApplication.toast("what:$what extra:$extra")
            }
            true
        }
    /**
     * ------------------------------------ player event listener end -------------------------------------------------
     */


    fun onResume() {
    }

    fun ismIsOnPause(): Boolean {
        return isPause
    }

    /**
     * MediaController
     */
    fun getCurrentTime(): Int {
        return playerView?.currentPosition?:0
    }

    fun getTotalTime(): Int {
        return return playerView?.duration?:0
    }

    /**
     * ------------------------------------ activity related start -------------------------------------------------
     */
    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            return if (isFullScreen) {
                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT.also { (context as AbsPlayerActivity?)?.requestedOrientation = it }
                true
            } else {
                (context as AbsPlayerActivity?)?.finish()
                true
            }
        }
        return false
    }

    fun onPause() {
        pauseVideo()
    }


    fun onDestroy() {
        if(disposable?.isDisposed==false){
            disposable?.dispose()
        }
        dismissHandler.removeCallbacks(runnable)
        clearVideoView()
        if (playerView != null) {
            playerView?.stopPlayback()
            playerView = null
        }
        mPlayerConfig = null
    }

    private fun clearVideoView() {
        controlParent?.removeAllViews()
        playerView?.let {
            it.setOnPreparedListener(null)
            it.setOnInfoListener(null)
            it.setOnErrorListener(null)
            it.setOnCompletionListener(null)
            it.setOnBufferingUpdateListener(null)
        }

    }

    fun onScreenRotate(configuration: Configuration?) {
        if(isScreenControlShowing){
            controlParent?.removeAllViews()
        }
        if(configuration?.orientation==Configuration.ORIENTATION_LANDSCAPE){//横屏
            isFullScreen=true
            mBackArrow?.visibility = GONE
            toFullScreen()
        }else if(configuration?.orientation==Configuration.ORIENTATION_PORTRAIT){//竖屏
            isFullScreen=false
            mBackArrow?.visibility = VISIBLE
            toHalfScreen()
        }
    }

    /**
     * 开始播放
     * 更新按钮状态
     * 2018/01/24 特殊情况(来电/分享)暂停/开始使用
     */
    fun startVideo() {
        isPause=false
        initProgress()
        playerView?.start()
        vScreenController?.showPlaying()
        hScreenController?.showPlaying()
    }

    /**
     * 暂停播放
     * 更新按钮状态
     * 2018/01/24 特殊情况暂停/开始使用
     */
    fun pauseVideo() {
        isPause=true
        uploadProgress()
        playerView?.pause()
        vScreenController?.showPause()
        hScreenController?.showPause()
    }



    fun hidePlayCompleteView() {
//        if (mPlayCompleteView != null) {
//            mPlayCompleteView.hideMonitorView()
//        }
    }


    fun hideMonitorView() {
//        if (mMonitorVew != null) {
//            mMonitorVew.hideMonitorView()
//        }
    }

    /**
     * 初始化断网监听器
     * @param listener
     */
    fun initNetError(listener: OnClickListener?) {
        if (netError != null) {
            netError?.initListener(listener)
        }
    }

    fun setmIsOnPause(pause: Boolean) {
//        this.mIsOnPause = pause
    }

    fun refreshCurrentPlay() {
//        if (controlParent != null) {
//            controlParent.refreshCurrentPlay()
//        }
    }


    /**
     * 调整播放进度
     */
    private fun adjustSeekStart(movedX: Float) {
        if(showViewType!=ShowViewType.SeekMonitorView){
            showSeekMonitor()
            seekMonitor?.initMonitorView(playerView?.currentPosition?:0,playerView?.duration?:1)
        }
        seekMonitor?.seekStart(movedX)
    }

    /**
     * 调整音量大小
     */
    private fun adjustVolumn(f: Float) {
        if(showViewType!=ShowViewType.VolumnView){
            showVolumn()
        }
        if (playerView?.audioVolumeMagX?:0 > 0) {
            playerView?.audioVolumeMagX = 2
        }
        volumn?.adjustVolume(mPlayerConfig?.mActivity, f)
    }

    /**
     * 调整屏幕亮度
     */
    private fun adjustBrightness(f: Float) {
        if(showViewType!=ShowViewType.BrightnessView){
            showBrightNess()
        }
        brightness?.adjustBrightness(mPlayerConfig?.mActivity, f)
    }

    fun showPlayCompleteView() {
        removeAllChildView()
        showViewType=ShowViewType.CompleteView
        controlParent?.addView(complete)
    }

    fun showVolumn(){
        removeAllChildView()
        showViewType=ShowViewType.VolumnView
        controlParent?.addView(volumn)
    }

    fun showBrightNess(){
        removeAllChildView()
        showViewType=ShowViewType.BrightnessView
        controlParent?.addView(brightness)
    }

    fun showSeekMonitor(){
        removeAllChildView()
        showViewType=ShowViewType.SeekMonitorView
        controlParent?.addView(seekMonitor)
    }

    fun showControlView(){
        dismissHandler.removeCallbacks(runnable)
        if(isFullScreen){
            showHControlView()
        }else{
            showVControlView()
        }
        dismissHandler.postDelayed(runnable, 3000) //3000毫秒后执行
    }

    fun showLoadingView(){
        removeAllChildView()
        showViewType=ShowViewType.LoadingView
        controlParent?.addView(loading)
    }

    fun showNetErrorView(){
        removeAllChildView()
        showViewType=ShowViewType.NetErrorView
        controlParent?.addView(netError)
    }

    fun showVControlView(){
        showViewType=ShowViewType.VScreenView
        controlParent?.addView(vScreenController)
    }

    fun showHControlView(){
        showViewType=ShowViewType.HScreenView
        controlParent?.addView(hScreenController)
    }


}

view_ielts_player.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/black">
    <org.koo.mediaplayer.KoolVideoView
        android:id="@+id/playerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    <com.koo.ieltspro2019.player.ui.ControllerView
        android:id="@+id/controlParent"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    <ImageView
        android:id="@+id/mBackArrow"
        android:layout_width="34dp"
        android:layout_height="34dp"
        android:padding="5dp"
        android:layout_marginTop="22dp"
        android:layout_marginLeft="15dp"
        android:src="@drawable/icon_player_back" />
</RelativeLayout>

其中playerView是安卓具体播放器,其他view都是上层显示

所有控制view的父类 ControllerView.java

他处理接收用户在视频界面的点击滑动手指抬起等操作,并把相关结果传递给子类接口

public class ControllerView extends RelativeLayout {

    private static final String TAG = "ControllerView";

    private static float X_TOLERANCE = 0.0f;
    private static float Y_TOLERANCE = 0.0f;
    private DisplayInformationFetcher mDisplayInformationFetcher;
    private DisplayMetrics mDisplayMetrics;
    private boolean mDownLeftRegion = false;
    private boolean mDownRightRegion = false;
    private OnControlEventListener mGestureListener;
    private boolean mMoved = false;
    private boolean mMovedCenter = false;
    private boolean mMovedLeft = false;
    private boolean mMovedRight = false;
    private float mTouchStartY = -1.0f;
    private float mX = 0.0f;
    private float mY = 0.0f;

    public interface OnControlEventListener {
        int REGION_CENTER = 2;
        int REGION_LEFT = 0;
        int REGION_RIGHT = 1;

        void onTap(int i);

        void onTouchMove(int i, float f, float f2);

        void onTouchUp(int i);
    }

    public ControllerView(Context context, AttributeSet attributeSet, int i) {
        super(context, attributeSet, i);
        init();
    }

    public ControllerView(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
        init();
    }

    public ControllerView(Context context) {
        super(context);
        init();
    }

    private void init() {
        this.mDisplayInformationFetcher = DisplayInformationFetcher.getInstance(getContext().getApplicationContext());
        this.mDisplayMetrics = this.mDisplayInformationFetcher.getDisplayMetrics();
        Y_TOLERANCE = this.mDisplayMetrics.density * 10.0f;
        X_TOLERANCE = this.mDisplayMetrics.density * 10.0f;
        setFocusable(true);
        setFocusableInTouchMode(true);
        setClickable(true);
    }

    public void setGestureListener(OnControlEventListener onControlEventListener) {
        this.mGestureListener = onControlEventListener;
    }

    @Override
    @SuppressLint({"ClickableViewAccessibility"})
    public boolean onTouchEvent(MotionEvent motionEvent) {
        if (!isClickable()) {
            return false;
        }
        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
            this.mTouchStartY = motionEvent.getY();
            touchStart(motionEvent.getX(), motionEvent.getY());
        } else if (this.mTouchStartY >= 0.0f && this.mTouchStartY < ((float) 10)) {
            return false;
        } else {
            if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
                this.mTouchStartY = -1.0f;
                touchMove(motionEvent.getX(), motionEvent.getY());
            } else if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
                touchUp(motionEvent.getX(), motionEvent.getY());
                this.mTouchStartY = -1.0f;
            }
        }
        return true;
    }

    private void touchStart(float getX, float getY) {
        int screenWidth = this.mDisplayInformationFetcher.getScreenWidth();
        this.mX = getX;
        this.mY = getY;
        this.mMovedLeft = false;
        this.mMovedRight = false;
        this.mMovedCenter = false;
        if (this.mX <= ((float) (screenWidth / 2))) {
            this.mDownLeftRegion = true;
        } else if (this.mX >= ((float) (screenWidth - (screenWidth / 2)))) {
            this.mDownRightRegion = true;
        }
    }

    private void touchMove(float getX, float getY) {
        float f3 = getX - this.mX;
        float f4 = getY - this.mY;
        float abs = Math.abs(f3);
        float abs2 = Math.abs(f4);
        if (abs2 > Y_TOLERANCE && ((abs2 > abs || this.mMovedLeft || this.mMovedRight) && !this.mMovedCenter)) {
            if (this.mDownLeftRegion) {
                this.mMovedLeft = true;
                if (this.mGestureListener != null) {
                    this.mGestureListener.onTouchMove(OnControlEventListener.REGION_LEFT, f3, f4);
                }
                this.mMoved = true;
                this.mX = getX;
                this.mY = getY;
            }
            if (this.mDownRightRegion) {
                this.mMovedRight = true;
                if (this.mGestureListener != null) {
                    this.mGestureListener.onTouchMove(OnControlEventListener.REGION_RIGHT, f3, f4);
                }
                this.mMoved = true;
                this.mX = getX;
                this.mY = getY;
            }
        } else if (abs <= X_TOLERANCE) {
        } else {
            if ((abs >= abs2 || this.mMovedCenter) && !this.mMovedLeft && !this.mMovedRight) {
                this.mMovedCenter = true;
                if (this.mGestureListener != null) {
                    this.mGestureListener.onTouchMove(OnControlEventListener.REGION_CENTER, f3, f4);
                }
                this.mMoved = true;
            }
        }
    }

    private void touchUp(float lastX, float lastY) {
        if (this.mMoved) {
            if (this.mGestureListener != null) {
                if (this.mMovedLeft) {
                    this.mGestureListener.onTouchUp(OnControlEventListener.REGION_LEFT);
                } else if (this.mMovedRight) {
                    this.mGestureListener.onTouchUp(OnControlEventListener.REGION_RIGHT);
                } else if (this.mMovedCenter) {
                    this.mGestureListener.onTouchUp(OnControlEventListener.REGION_CENTER);
                }
            }
        } else if (this.mGestureListener != null) {
            this.mGestureListener.onTap(OnControlEventListener.REGION_CENTER);
        }
        this.mMoved = false;
        this.mDownLeftRegion = false;
        this.mDownRightRegion = false;
    }
}

竖屏显示view VScreenController.kt

class VScreenController(context: Context, attrs: AttributeSet? = null) :BaseWidget(context,attrs) {
    private var mPause: ImageView? = null
    private var ivFullscreen: ImageView? = null
    private var mSeekBar: MarkSeekBar? = null
    private var mCurTime:TextView? = null
    private var mSplit:TextView? = null
    private var mEndTime:TextView? = null
    var toFullScreen:() -> Unit={}
    var pauseOrPlayClick:()->Unit={}
    var seekTo:(position:Int)->Unit={}
    var mTotalTime:Int=0
    var isDragStart = false
    override fun initView() {
        mPause = view?.findViewById(R.id.iv_pause)
        mSeekBar = view?.findViewById(R.id.sb_progress)
        mCurTime = view?.findViewById(R.id.tv_cur_time)
        mSplit = view?.findViewById(R.id.iv_split)
        mEndTime = view?.findViewById(R.id.tv_end_time)
        ivFullscreen = view?.findViewById(R.id.ivFullscreen)
    }

    override fun initInnerEvent() {

        mPause?.setOnClickListener{
            pauseOrPlayClick()
        }
        ivFullscreen?.setOnClickListener{
            toFullScreen()
        }

        mSeekBar?.setOnProgressChangedListener(SeekBarChangeEvent())
    }

    inner class SeekBarChangeEvent : OnProgressChangedListener {
        override fun onProgressChanged(
            signSeekBar: MarkSeekBar,
            progress: Float,
            fromUser: Boolean
        ) {
            isDragStart = true
            mCurTime?.text = DKTimeFormatter.getInstance().stringForTime(progress.toInt())
        }

        override fun getProgressOnActionUp(signSeekBar: MarkSeekBar, progress: Float) {
            seekTo(progress.toInt())
            // 个别机型(vivo)单击进度条时按下状态没有置回,手动置回状态
            if (mSeekBar?.isPressed ==true) {
                mSeekBar?.isPressed = false
            }
            isDragStart = false
        }
    }

    fun setTotalTime(totalTime:Int){
        mTotalTime = totalTime
        mSeekBar?.max=totalTime.toFloat()
        mEndTime?.text = DKTimeFormatter.getInstance().stringForTime(mTotalTime)
    }
    fun updateProgress(position:Int) {
        if(!isDragStart){
            mCurTime?.text = DKTimeFormatter.getInstance().stringForTime(position)
            if (mSeekBar != null && mTotalTime > 0) {
                mSeekBar?.progress = position.toFloat()
            }
        }
    }
    fun updateSecondCache(cacheTime: Int,mTotalTime:Int) {
        if (mSeekBar != null && mTotalTime > 0) {
            mSeekBar?.setCacheProgress((cacheTime * 1000).toFloat())
        }
    }

    fun showPlaying(){
        mPause?.setImageResource(R.drawable.player_pause_01)
    }

    fun showPause(){
        mPause?.setImageResource(R.drawable.player_pause_16)
    }

    /**
     * 播放完成展示
     */
    fun showPlayEnd(){
        mSeekBar?.progress = mSeekBar?.max ?:100.toFloat()
        mCurTime?.text = DKTimeFormatter.getInstance().stringForTime(mTotalTime)
        mEndTime?.text = DKTimeFormatter.getInstance().stringForTime(mTotalTime)
    }


    override fun getLayoutId() = R.layout.player_v_controller
}

竖屏显示view布局 player_v_controller.xml

package com.koo.ieltspro2019.player.view

import android.content.Context
import android.util.AttributeSet
import android.widget.ImageView
import android.widget.TextView
import com.koo.android.view.basewidget.BaseWidget
import com.koo.ieltspro2019.R
import com.koo.ieltspro2019.player.ui.utils.DKTimeFormatter
import com.koo.ieltspro2019.view.MarkSeekBar
import com.koo.ieltspro2019.view.MarkSeekBar.OnProgressChangedListener

class VScreenController(context: Context, attrs: AttributeSet? = null) :BaseWidget(context,attrs) {
    private var mPause: ImageView? = null
    private var ivFullscreen: ImageView? = null
    private var mSeekBar: MarkSeekBar? = null
    private var mCurTime:TextView? = null
    private var mSplit:TextView? = null
    private var mEndTime:TextView? = null
    var toFullScreen:() -> Unit={}
    var pauseOrPlayClick:()->Unit={}
    var seekTo:(position:Int)->Unit={}
    var mTotalTime:Int=0
    var isDragStart = false
    override fun initView() {
        mPause = view?.findViewById(R.id.iv_pause)
        mSeekBar = view?.findViewById(R.id.sb_progress)
        mCurTime = view?.findViewById(R.id.tv_cur_time)
        mSplit = view?.findViewById(R.id.iv_split)
        mEndTime = view?.findViewById(R.id.tv_end_time)
        ivFullscreen = view?.findViewById(R.id.ivFullscreen)
    }

    override fun initInnerEvent() {

        mPause?.setOnClickListener{
            pauseOrPlayClick()
        }
        ivFullscreen?.setOnClickListener{
            toFullScreen()
        }

        mSeekBar?.setOnProgressChangedListener(SeekBarChangeEvent())
    }

    inner class SeekBarChangeEvent : OnProgressChangedListener {
        override fun onProgressChanged(
            signSeekBar: MarkSeekBar,
            progress: Float,
            fromUser: Boolean
        ) {
            isDragStart = true
            mCurTime?.text = DKTimeFormatter.getInstance().stringForTime(progress.toInt())
        }

        override fun getProgressOnActionUp(signSeekBar: MarkSeekBar, progress: Float) {
            seekTo(progress.toInt())
            // 个别机型(vivo)单击进度条时按下状态没有置回,手动置回状态
            if (mSeekBar?.isPressed ==true) {
                mSeekBar?.isPressed = false
            }
            isDragStart = false
        }
    }

    fun setTotalTime(totalTime:Int){
        mTotalTime = totalTime
        mSeekBar?.max=totalTime.toFloat()
        mEndTime?.text = DKTimeFormatter.getInstance().stringForTime(mTotalTime)
    }
    fun updateProgress(position:Int) {
        if(!isDragStart){
            mCurTime?.text = DKTimeFormatter.getInstance().stringForTime(position)
            if (mSeekBar != null && mTotalTime > 0) {
                mSeekBar?.progress = position.toFloat()
            }
        }
    }
    fun updateSecondCache(cacheTime: Int,mTotalTime:Int) {
        if (mSeekBar != null && mTotalTime > 0) {
            mSeekBar?.setCacheProgress((cacheTime * 1000).toFloat())
        }
    }

    fun showPlaying(){
        mPause?.setImageResource(R.drawable.player_pause_01)
    }

    fun showPause(){
        mPause?.setImageResource(R.drawable.player_pause_16)
    }

    /**
     * 播放完成展示
     */
    fun showPlayEnd(){
        mSeekBar?.progress = mSeekBar?.max ?:100.toFloat()
        mCurTime?.text = DKTimeFormatter.getInstance().stringForTime(mTotalTime)
        mEndTime?.text = DKTimeFormatter.getInstance().stringForTime(mTotalTime)
    }


    override fun getLayoutId() = R.layout.player_v_controller
}