一个音频播放的自定义view(需结合前面文章的辅助类使用)

358 阅读2分钟
  1. 辅助类基类

其中 BaseWidget 是自定义view的一个基类,大家可以自己实现.也可以参考本人另一篇 文章中的那些基类们直接复制

/**
 * 作者: zhangchenzhou
 * 时间: 2020/7/21-12:01
 * 说明:
 * 口语音频带进度条的播放view
 * 可以实现如下操作
 * 1. 暂停
 * 2. 开始
 * 3. 进度条拖动切换进度
 * 4. 显示总时间
 * 5. 实现换皮操作.
 */
public abstract class BaseAudioPlayView extends BaseWidget {
    AudioPlayHelper mPlayHelper;
    private PlayClickListener mOnClickListener;
    ImageView playBtn;
    SeekBar audioSeekBar;
    TextView audioTime;
    String playUrl;
    private boolean isSeekBarTracking = false;
    public BaseAudioPlayView(@NotNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        disableClickAndTD();
        mPlayHelper = AudioPlayHelper.getInstance();
    }

    @Override
    public void initView() {
        playBtn = findViewById(R.id.playBtn);
        audioSeekBar = findViewById(R.id.audioSeekBar);
        audioTime = findViewById(R.id.audioTime);
    }

    @Override
    public void initInnerEvent() {
        playBtn.setOnClickListener(v->{
            if(mOnClickListener!=null){
                mOnClickListener.onPlayClick();
            }
        });

        audioSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                isSeekBarTracking=true;
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                setProgress(seekBar.getProgress());
                if(mOnClickListener!=null){
                    mOnClickListener.onPlayWithPos(seekBar.getProgress());
                }
                isSeekBarTracking=false;
            }
        });
    }

    public void setPlayUrl(String playUrl) {
        this.playUrl = playUrl;
    }

    public void setAllTime(String allTime){
        audioTime.setText(allTime);
    }
    /**
     * 展示正在播放界面
     */
    abstract void showPlaying();

    /**
     * 暂时暂停界面
     */
    abstract void showPause();

    /**
     * 展示加载中界面
     */
    abstract void showLoading();

    /**
     * 设置进度,让子类可以接收到进度
     * @param position
     */
    public void setProgress(int position){
        if(!isSeekBarTracking){
            audioSeekBar.setProgress(position);
        }
    }

    /**
     * 设置进度总size
     * @param max
     */
    public void setProgressMax(int max){}

    /**
     * 播放按钮被点击的监听
     * @param mOnClickListener
     */
    public void setOnPlayClickListener(PlayClickListener mOnClickListener) {
        this.mOnClickListener = mOnClickListener;
    }

    public interface PlayClickListener{
        void onPlayClick();
        void onPlayWithPos(int pos);
    }

    public void disableClickAndTD(){
        //禁用状态
        audioSeekBar.setClickable(false);
        audioSeekBar.setEnabled(false);
        audioSeekBar.setFocusable(false);
    }

    public void enableClickAndTD(){
        audioSeekBar.setClickable(true);
        audioSeekBar.setEnabled(true);
        audioSeekBar.setFocusable(true);

    }
}
  1. 音频播放的子类实现,这样就可以把音频控件直接放到你的界面中,给他塞一个地址他就能自动播放,同时关闭页面时能自动销毁播放器
public class SpokenTopAudioPlayView extends BaseAudioPlayView {
    public static final String TAG_SPOKEN_TOP_AUDIO_VIEW = "SpokenTopAudioPlayView";
    public SpokenTopAudioPlayView(@NotNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        //需要处理列表中播放的情况,所以此处没有在父类中实现
        setOnPlayClickListener(new PlayClickListener() {
            @Override
            public void onPlayClick() {
                if(!TextUtils.isEmpty(playUrl)){
                    mPlayHelper.startPlay(TAG_SPOKEN_TOP_AUDIO_VIEW,playUrl,playUrl,mAudioPlayListener,-1);
                }
            }

            @Override
            public void onPlayWithPos(int pos) {
                mPlayHelper.startPlay(TAG_SPOKEN_TOP_AUDIO_VIEW,playUrl,playUrl,mAudioPlayListener,pos);
            }
        });
    }

    @Override
    void showPlaying() {
        playBtn.setImageResource(R.drawable.spoken_top_audio_play);
    }

    @Override
    void showPause() {
        playBtn.setImageResource(R.drawable.spoken_top_audio_pause);
    }
    public void resetView(){
        mPlayHelper.releaseByTag(TAG_SPOKEN_TOP_AUDIO_VIEW);
        audioSeekBar.setProgress(0);
    }
    @Override
    void showLoading() {
        playBtn.setImageResource(R.drawable.spoken_top_audio_play);
    }

    public void pendPlay(){
        if(!TextUtils.isEmpty(playUrl)){
            mPlayHelper.getMp3Length(playUrl, length -> {
                if(length!=-1){
                    mAudioPlayListener.allTimeInit(length*1000);
                }else{
                    mPlayHelper.pendPlay(playUrl,mAudioPlayListener);
                }
            });

        }
    }

    @Override
    public int getLayoutId() {
        return R.layout.view_audioplay;
    }

    private AudioPlayHelper.EasyAudioPlayListener mAudioPlayListener = new AudioPlayHelper.EasyAudioPlayListener() {
        @Override
        public void onPreparing() {//应该是加载中状态,此处变成暂停按钮
            showLoading();
        }

        @Override
        public void onPlaying() {
            showPlaying();
        }

        @Override
        public void onPause() {
            showPause();
        }

        @Override
        public void onRelease() {
            showPause();
            audioSeekBar.setProgress(0);
        }

        @Override
        public void onError() {
            showPause();
        }

        @Override
        public void onPositionChanged(long position) {
            audioSeekBar.setProgress((int)position);
        }

        @Override
        public void allTimeInit(long time) {
            audioSeekBar.setMax((int)time);
            setAllTime(TimeUtil.getMiaoFenOptional((int)time / 1000));
            enableClickAndTD();
        }

        @Override
        public void onCompletion() {
            showPause();
            audioSeekBar.setProgress(audioSeekBar.getMax());
        }
    };
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mPlayHelper.release(TAG_SPOKEN_TOP_AUDIO_VIEW,playUrl);
    }
}

布局view_audioplay.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="@drawable/bg_corner_e6e8f1_radius25"
    android:gravity="center_vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/playBtn"
        android:layout_marginLeft="@dimen/x8"
        android:src="@drawable/spoken_top_audio_pause"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <com.k.ie.ui.DisableClickSeekBar
        android:id="@+id/audioSeekBar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:maxHeight="@dimen/x2"
        android:minHeight="@dimen/x2"
        tools:progress="30"
        android:progressDrawable="@drawable/spoken_top_seekbar_bg"
        android:thumb="@drawable/spoken_top_seekbar_thumb"
        android:layout_weight="1" />
    <TextView
        android:id="@+id/audioTime"
        tools:text="02'00"
        android:layout_marginRight="@dimen/x16"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>
  1. 列表中播放的子类实现,此子类需要结合列表中的实际逻辑进行播放处理
public class SpokenListAudioPlayView extends BaseAudioPlayView {
    public SpokenListAudioPlayView(@NotNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void showPlaying() {
        playBtn.setImageResource(R.drawable.spoken_list_audio_play);
    }

    @Override
    public void showPause() {
        playBtn.setImageResource(R.drawable.spoken_list_audio_pause);
    }

    @Override
    public void showLoading() {
        playBtn.setImageResource(R.drawable.spoken_list_audio_play);
    }

    @Override
    public void setProgressMax(int max) {
        audioSeekBar.setMax(max);
        enableClickAndTD();
    }

    @Override
    public int getLayoutId() {
        return R.layout.view_audioplay_list;
    }
}

对应布局view_audioplay_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="@drawable/bg_corner_e6e8f1_radius25"
    android:gravity="center_vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/playBtn"
        android:layout_marginLeft="@dimen/x10"
        android:padding="@dimen/x5"
        android:src="@drawable/spoken_list_audio_pause"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <com.k.ie.ui.DisableClickSeekBar
        android:id="@+id/audioSeekBar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="-5dp"
        android:layout_marginRight="-5dp"
        android:maxHeight="@dimen/x2"
        android:minHeight="@dimen/x2"
        tools:progress="30"
        android:progressDrawable="@drawable/spoken_list_seekbar_bg"
        android:thumb="@drawable/spoken_list_seekbar_thumb"
        android:layout_weight="1" />
    <TextView
        android:id="@+id/audioTime"
        tools:text="02'00"
        android:layout_marginRight="@dimen/x12"
        android:textColor="@color/C_FF32374E"
        android:textSize="@dimen/x12"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>
  1. 图片资源