RecyclerView 视频

例:

.......

点击打开链接

1.项目框架模式:MVP(得分点);注意:分包分避免内存泄漏;

2.图片加载:Fresco图片加载框架;

3.络加载框架:retrofit;使用Retrofit+RxJava+okHttp实现网络加载;

5.列表数据展示使用RecyclerView;


1MVP分包明确,避免内存泄漏必须对PV层抽取基类,否则无分

2、访问网络接口使用retrofit+Rxjava必须封装retrofit单例工具类,否则无分

3、图片展示使用Fresco图片加载框架,视频展示自由选择播放器;

4、使用RecyclerView实现图一图二所示的视频模块和图片模块,

5、左右滑动可以相互切换当前模块

6、给RecyclerView添加分割线

7、数据必须解析正确,必须使用retrofitRxjava

8图片模块可能包含GIF使用is_gif 字段判断

9、最终效果和图一图二保持一致,视频能够正确播放


依赖:

 
dependencies {  compile 'com.android.support.constraint:constraint-layout:1.0.2'  testCompile 'junit:junit:4.12'  compile 'jp.wasabeef:glide-transformations:2.0.1'  compile 'com.android.support:cardview-v7:22.2.1'  implementation 'com.android.support:recyclerview-v7:26.1.0' }


权限:

<uses-permission android:name="android.permission.INTERNET"/>


主方法类:

public class MainActivity extends AppCompatActivity {
    private Toolbar toolbar;
    private RecyclerView recyclerView;
    private VideoRecyclerAdapter mAdapter;
    private FrameLayout videoRootViewFl;
    private MyVideoView videoView;
    private FrameLayout fullScreen;
    private View lastView;
    private int videoPosition = -1;
    private List<VideoBean> videoBeanList = new ArrayList<>();
    private int[] imageIds = new int[]{R.drawable.hzw_a, R.drawable.hzw_b,
            R.drawable.hzw_d, R.drawable.hzw_e, R.drawable.hzw_f, R.drawable.hzw_h,
            R.drawable.hzw_i, R.drawable.hzw_j, R.drawable.hzw_k};

    private static String VIDEO_PATH = "http://dn-chunyu.qbox.me/fwb/static/images/home/video/video_aboutCY_A.mp4";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();
        initEvent();
    }

    private void initView() {
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        ActionBar supportActionBar = getSupportActionBar();
        if (supportActionBar != null) {
            supportActionBar.setDisplayHomeAsUpEnabled(true);
            supportActionBar.setHomeAsUpIndicator(R.drawable.ic_menu_white_24dp);
            supportActionBar.setTitle("");
        }
        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        videoRootViewFl = (FrameLayout) findViewById(R.id.video_root_fl);
        fullScreen = (FrameLayout) findViewById(R.id.video_full_screen);
        mAdapter = new VideoRecyclerAdapter(videoBeanList);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(mAdapter);
    }

    private void showVideo(View view, final String videoPath) {
        View v;
        removeVideoView();
        if (videoRootViewFl.getVisibility() == View.VISIBLE) {
            videoRootViewFl.removeAllViews();
            videoRootViewFl.setVisibility(View.GONE);
        }
        if (videoView == null) {
            videoView = new MyVideoView(MainActivity.this);
// videoView.setListener(new MyVideoView.IFullScreenListener() { // @Override // public void onClickFull(boolean isFull) { // if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) { // fullScreen.setVisibility(View.VISIBLE); // removeVideoView(); // setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); // fullScreen.addView(videoView, new ViewGroup.LayoutParams(-1, -1)); // videoView.setVideoPath(VIDEO_PATH); // videoView.start(); // } else { // fullScreen.removeAllViews(); // fullScreen.setVisibility(View.GONE); // setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); // if (lastView instanceof ViewGroup) { // ((ViewGroup) lastView).addView(videoView); // } // videoView.setVideoPath(VIDEO_PATH); // videoView.start(); // } // // } // })  }
        videoView.stop();
        v = view.findViewById(R.id.item_imageview);
        if (v != null) v.setVisibility(View.INVISIBLE);
        v = view.findViewById(R.id.item_image_play);
        if (v != null) v.setVisibility(View.INVISIBLE);
        v = view.findViewById(R.id.item_video_root_fl);
        if (v != null) {
            v.setVisibility(View.VISIBLE);
            FrameLayout fl = (FrameLayout) v;
            fl.removeAllViews();
            fl.addView(videoView, new ViewGroup.LayoutParams(-1, -1));
            VIDEO_PATH = videoPath;
            videoView.setVideoPath(videoPath);
            videoView.start();
        }
        lastView = view;
    }
    private void removeVideoView() {
        View v;
        if (lastView != null) {
            v = lastView.findViewById(R.id.item_imageview);
            if (v != null) v.setVisibility(View.VISIBLE);
            v = lastView.findViewById(R.id.item_image_play);
            if (v != null) v.setVisibility(View.VISIBLE);
            v = lastView.findViewById(R.id.item_video_root_fl);
            if (v != null) {
                FrameLayout ll = (FrameLayout) v;
                ll.removeAllViews();
                v.setVisibility(View.GONE);
            }
        }
    }
    private void initData() {
        VideoBean videoBean;
        for (int i = 0; i < 100; i++) {
            videoBean = new VideoBean(imageIds[i % imageIds.length], VIDEO_PATH);
            videoBeanList.add(videoBean);
        }
    }
    private void initEvent() {
        mAdapter.setListener(new VideoRecyclerAdapter.OnClickPlayListener() {
            @Override
            public void onPlayClick(View view, String videoPath) {
                showVideo(view, videoPath);
            }
        });
        recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
            @Override
            public void onChildViewAttachedToWindow(View view) {
                if (videoPosition == -1 || videoRootViewFl.getVisibility() != View.VISIBLE) {
                    return;
                }
                if (videoPosition == recyclerView.getChildAdapterPosition(view)) {
                    videoPosition = -1;
                    showVideo(view, VIDEO_PATH);
                }
            }
            @Override
            public void onChildViewDetachedFromWindow(View view) {
                if (videoView == null || videoRootViewFl.getVisibility() == View.VISIBLE) return;
                View v = view.findViewById(R.id.item_video_root_fl);
                if (v != null) {
                    FrameLayout fl = (FrameLayout) v;
                    videoPosition = recyclerView.getChildAdapterPosition(view);
                    if (fl.getChildCount() > 0) {
                        fl.removeAllViews();
                        int position = 0;
                        if (videoView.isPlaying()) {
                            position = videoView.getPosition();
                            videoView.stop();
                        }
                        videoRootViewFl.setVisibility(View.VISIBLE);
                        videoRootViewFl.removeAllViews();
                        lastView = videoRootViewFl;
                        videoRootViewFl.addView(videoView, new ViewGroup.LayoutParams(-1, -1));
                        videoView.setVideoPath(VIDEO_PATH);
                        videoView.start();
                        videoView.seekTo(position);
// if (videoView.isPause()) { // videoView.resume(); // }  }
                    fl.setVisibility(View.GONE);
                }
                v = view.findViewById(R.id.item_imageview);
                if (v != null) {
                    if (v.getVisibility() != View.VISIBLE) {
                        v.setVisibility(View.VISIBLE);
                    }
                }
                v = view.findViewById(R.id.item_image_play);
                if (v != null) {
                    if (v.getVisibility() != View.VISIBLE) {
                        v.setVisibility(View.VISIBLE);
                    }
                }
            }
        });
    }
    @Override
    protected void onDestroy() {
        if (videoView != null) {
            videoView.stop();
        }
        super.onDestroy();
    }
}


主方法布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">

    <android.support.design.widget.CoordinatorLayout  android:layout_width="match_parent"  android:layout_height="match_parent">

        <android.support.design.widget.AppBarLayout  android:layout_width="match_parent"  android:layout_height="wrap_content">

            <android.support.v7.widget.Toolbar  android:id="@+id/toolbar"  android:layout_width="match_parent"  android:layout_height="?attr/actionBarSize"  android:background="@color/colorPrimary"  app:layout_scrollFlags="scroll|enterAlways|snap" />
        </android.support.design.widget.AppBarLayout>

        <android.support.v7.widget.RecyclerView  android:id="@+id/recyclerView"  android:layout_width="match_parent"  android:layout_height="match_parent"  app:layout_behavior="@string/appbar_scrolling_view_behavior" />
    </android.support.design.widget.CoordinatorLayout>

    <!-- 右下角的FragmeLayout -->  <FrameLayout  android:id="@+id/video_root_fl"  android:layout_width="150dp"  android:layout_height="150dp"  android:layout_alignParentBottom="true"  android:layout_alignParentRight="true"  android:background="#000"  android:visibility="gone" />

    <!--全屏播放的FragmeLayout-->  <FrameLayout  android:id="@+id/video_full_screen"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:visibility="gone" />
</RelativeLayout>


VideoRecyclerAdapter 

public class VideoRecyclerAdapter extends RecyclerView.Adapter<VideoRecyclerAdapter.ViewHolder> {
    private List<VideoBean> mList;
    private OnClickPlayListener listener;
    public void setListener(OnClickPlayListener listener) {
        this.listener = listener;
    }
    public VideoRecyclerAdapter(List<VideoBean> list) {
        this.mList = list;
    }
    public void addVideoBean(VideoBean videoBean) {
        if (videoBean == null) return;
        if (mList == null) {
            mList = new ArrayList<>();
        }
        mList.add(videoBean);
        notifyDataSetChanged();
    }

    public void addAllVideoBean(List<VideoBean> list) {
        if (list == null) return;
        if (mList == null) {
            mList = new ArrayList<>();
        }
        mList.clear();
        mList.addAll(list);
        notifyDataSetChanged();
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_video, parent, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        final VideoBean videoBean = mList.get(position);
        Glide.with(holder.itemView.getContext()).load(videoBean.mImageId).crossFade().into(holder.mImageView);
        holder.mImageViewPlay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (listener != null) {
                    listener.onPlayClick(holder.mCardView, videoBean.mVideoPath);
                }
            }
        });
    }

    @Override
    public int getItemCount() {
        if (mList == null) return 0;
        return mList.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        CardView mCardView;
        FrameLayout mVideoRootFl;
        ImageView mImageView;
        ImageView mImageViewPlay;

        public ViewHolder(View itemView) {
            super(itemView);
            mCardView = (CardView) itemView.findViewById(R.id.item_cardview);
            mVideoRootFl = (FrameLayout) itemView.findViewById(R.id.item_video_root_fl);
            mImageView = (ImageView) itemView.findViewById(R.id.item_imageview);
            mImageViewPlay = (ImageView) itemView.findViewById(R.id.item_image_play);
        }
    }

    public interface OnClickPlayListener {
        void onPlayClick(View view, String videoPath);
    }
}

item_video

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:app="http://schemas.android.com/apk/res-auto"  android:id="@+id/item_cardview"  android:layout_width="match_parent"  android:layout_height="200dp"  android:layout_margin="10dp"  android:background="#fff"  android:elevation="8dp"  android:padding="5dp"  app:cardBackgroundColor="#fff"  app:cardCornerRadius="5dp">

    <!--列表播放使用的FrameLayout-->  <FrameLayout  android:id="@+id/item_video_root_fl"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:visibility="gone" />

    <ImageView  android:id="@+id/item_imageview"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:scaleType="centerCrop" />

    <ImageView  android:id="@+id/item_image_play"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:layout_gravity="center"  android:src="@drawable/ic_play_circle_outline_white_48dp" />
</android.support.v7.widget.CardView>


VideoBean 

public class VideoBean {
    public int mImageId;
    public String mVideoPath;
    public VideoBean(int imageId, String videoPath) {
        this.mImageId = imageId;
        this.mVideoPath = videoPath;
    }
}

MyVideoView 

public class MyVideoView extends RelativeLayout {
    private View rootLayout;
    private VideoView videoView;
    private View mClickView;
    private ImageView playOrPauseCenterIv;
    private LinearLayout playControlLl;
    private ImageView playOrPauseIv;
    private SeekBar seekBar;
    private ImageView fullIv;
    private static final int SHOW_CONTROL = 0x0001;
    private static final int HIDE_CONTROL = 0x0002;
    private static final int UPDATE_POSITION = 0x0003;
    private boolean isTrackingTouch = false;
    private boolean isShowControl = false;
    private boolean isPause = false;
    private boolean isFull = false;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SHOW_CONTROL:
                    showControLl();
                    break;
                case HIDE_CONTROL:
                    hideControLl();
                    break;
                case UPDATE_POSITION:
                    updatePosition();
                    break;
                default:
                    break;
            }
        }
    };

    private IFullScreenListener listener;
    public void setListener(IFullScreenListener listener) {
        this.listener = listener;
    }
    public MyVideoView(Context context) {
        super(context);
        init();
    }
    public MyVideoView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    public MyVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MyVideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }
    private void init() {
        rootLayout = LayoutInflater.from(getContext()).inflate(R.layout.video_view, this, true);
        mClickView = findViewById(R.id.my_video_click);
        videoView = (VideoView) findViewById(R.id.my_videoview);
        playOrPauseCenterIv = (ImageView) findViewById(R.id.my_video_center_playpause_iv);
        playControlLl = (LinearLayout) findViewById(R.id.my_video_play_control_ll);
        playOrPauseIv = (ImageView) findViewById(R.id.my_video_play_pause_iv);
        seekBar = (SeekBar) findViewById(R.id.my_video_seekbar);
        fullIv = (ImageView) findViewById(R.id.my_video_full_iv);
        initSetting();
        initEvent();
    }
    private void initSetting() {
        playOrPauseCenterIv.setImageResource(R.drawable.ic_play_circle_outline_white_48dp);
        showControLl();
        playOrPauseIv.setImageResource(R.drawable.ic_play_circle_outline_white_24dp);
        seekBar.setProgress(0);
        fullIv.setImageResource(R.drawable.ic_fullscreen_white_24dp);
        seekBar.setEnabled(false);
    }
    private void initEvent() {
        videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                stop();
            }
        });
        videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                //TODO  return false;
            }
        });
        videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                playOrPauseIv.setImageResource(R.drawable.ic_pause_circle_outline_white_24dp);
                playOrPauseCenterIv.setImageResource(R.drawable.ic_pause_circle_outline_white_48dp);
                seekBar.setMax(mp.getDuration());
                seekBar.setProgress(mp.getCurrentPosition());
                seekBar.setEnabled(true);
                handler.sendEmptyMessage(UPDATE_POSITION);
            }
        });
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

            }
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                isTrackingTouch = true;
                handler.removeMessages(HIDE_CONTROL);
            }
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                isTrackingTouch = false;
                handler.sendEmptyMessageDelayed(HIDE_CONTROL, 3000);
                int position = seekBar.getProgress();
                if (videoView.isPlaying()) {
                    videoView.seekTo(position);
                }
            }
        });
        mClickView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isShowControl) {
                    hideControLl();
                } else {
                    showControLl();
                }
            }
        });
        playOrPauseIv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (videoView.isPlaying()) {
                    pause();
                } else {
                    resume();
                }
            }
        });
        playOrPauseCenterIv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (videoView.isPlaying()) {
                    pause();
                } else {
                    resume();
                }
            }
        });
        fullIv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                isFull = !isFull;
                setFullScreen(isFull);
                if (listener != null) {
                    listener.onClickFull(isFull);
                }
            }
        });
    }
    /**  * 更新进度  */  private void updatePosition() {
        handler.removeMessages(UPDATE_POSITION);
        if (videoView.isPlaying()) {
            int currentPosition = videoView.getCurrentPosition();
            if (!isTrackingTouch) {
                seekBar.setProgress(currentPosition);
            }
            handler.sendEmptyMessageDelayed(UPDATE_POSITION, 500);
        }
    }
    /**  * 隐藏控制条  */  public void hideControLl() {
        isShowControl = false;
        handler.removeMessages(HIDE_CONTROL);
        playOrPauseCenterIv.setVisibility(View.GONE);
        playControlLl.clearAnimation();
        playControlLl.animate().translationY(playControlLl.getHeight()).setDuration(500).start();
    }
    /**  * 显示控制条  */  public void showControLl() {
        isShowControl = true;
        handler.sendEmptyMessageDelayed(HIDE_CONTROL, 3000);
        playOrPauseCenterIv.setVisibility(View.VISIBLE);
        playControlLl.clearAnimation();
        playControlLl.animate().translationY(0).setDuration(500).start();
    }
    /**  * 设置播放地址  * @param path  */  public void setVideoPath(String path) {
        videoView.setVideoPath(path);
    }
    /**  * 开始播放  */  public void start() {
        isPause = false;
        videoView.start();
        showControLl();
    }
    /**  * 是否正在播放  * @return  */  public boolean isPlaying() {
        return videoView.isPlaying();
    }

    /**  * 暂停  */  public void pause() {
        isPause = true;
        handler.removeMessages(UPDATE_POSITION);
        videoView.pause();
        playOrPauseCenterIv.setImageResource(R.drawable.ic_play_circle_outline_white_48dp);
        playOrPauseIv.setImageResource(R.drawable.ic_play_circle_outline_white_24dp);
    }
    /**  * 是否处于暂停状态  * @return  */  public boolean isPause() {
        return isPause;
    }
    /**  * 继续  */  public void resume() {
        isPause = false;
        handler.sendEmptyMessageDelayed(UPDATE_POSITION, 500);
        videoView.start();
        playOrPauseCenterIv.setImageResource(R.drawable.ic_pause_circle_outline_white_48dp);
        playOrPauseIv.setImageResource(R.drawable.ic_pause_circle_outline_white_24dp);
    }
    public int getPosition() {
        return videoView.getCurrentPosition();
    }
    public void seekTo(int position) {
        videoView.seekTo(position);
    }
    /**  * 停止  */  public void stop() {
        initSetting();
        handler.removeCallbacksAndMessages(null);
        videoView.stopPlayback();
    }
    private void setFullScreen(boolean fullScreen) {
        if (getContext() != null && getContext() instanceof AppCompatActivity) {
            ActionBar supportActionBar = ((AppCompatActivity) getContext()).getSupportActionBar();
            if (supportActionBar != null) {
                if (fullScreen) {
                    supportActionBar.hide();
                } else {
                    supportActionBar.show();
                }
            }
        }
    }
    public interface IFullScreenListener {
        void onClickFull(boolean isFull);
    }
}
video_view
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:id="@+id/my_video_layout"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:background="#000">
    <VideoView  android:id="@+id/my_videoview"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_centerInParent="true" />
    <View  android:id="@+id/my_video_click"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:background="#00ffffff" />
    <ImageView  android:id="@+id/my_video_center_playpause_iv"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:layout_centerInParent="true"  android:src="@drawable/ic_play_circle_outline_white_48dp" />
    <LinearLayout  android:id="@+id/my_video_play_control_ll"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_alignParentBottom="true"  android:background="#88cccccc"  android:gravity="center_vertical"  android:orientation="horizontal"  android:padding="3dp">
        <ImageView  android:id="@+id/my_video_play_pause_iv"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:src="@drawable/ic_play_circle_outline_white_24dp" />
        <SeekBar  android:id="@+id/my_video_seekbar"  android:layout_width="0dp"  android:layout_height="wrap_content"  android:layout_weight="1" />
        <ImageView  android:id="@+id/my_video_full_iv"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:src="@drawable/ic_fullscreen_white_24dp" />
    </LinearLayout>
</RelativeLayout>

点击打开链接