preface

In the last article, we realized the effect of turning up and down pages to switch videos in imitation of Douyin. In this article, we will realize douyin list playing videos.

  • [Android Advanced] Imitation Douyin series slide switch video (1)
  • [Android Advanced] Copy Douyin series list
  • [Android Advanced] Copy Douyin series list
  • [Android Advanced] Imitation Douyin series slide on the page switching video (4)
  • [Android Advanced] Video Preview and Recording of Douyin Series (5)

I also found a demo on Github before, here is the link, the principle is the same as mine, but it is more troublesome to use…

Train of thought

Here, onScrolled and onScrollStateChanged of RecyclerView are used to listen, and the visible position can be judged in onScrolled. In combination with the sliding state of current RecyclerView returned in onScrollStateChanged, it can play when dragging and stopping scrolling; Pause playback when sliding inertia.

tip: About 3 kinds of sliding states of Recyclerview. SCROLL_STATE_IDLE, recyclerview. SCROLL_STATE_DRAGGING, Recyclerview.scroll_state_demystified, which can be explained and explained.

rvList.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
                firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
                lastVisibleItem = layoutManager.findLastVisibleItemPosition();

            }

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                switch (newState) {
                    case RecyclerView.SCROLL_STATE_IDLE:// Stop scrolling
                        /** Execute here, the video automatically play and stop */
                        autoPlayVideo(recyclerView);
                        break;
                    case RecyclerView.SCROLL_STATE_DRAGGING:/ / drag
                        autoPlayVideo(recyclerView);
                        break;
                    case RecyclerView.SCROLL_STATE_SETTLING:// Inertial sliding
                        JZVideoPlayer.releaseAllVideos();
                        break; }}});Copy the code

The layout is a RecyclerView, will not paste, the following is Adapter

         urlList = new ArrayList<>();
        urlList.add("http://image.38.hn/public/attachment/201805/100651/201805181532123423.mp4");
        urlList.add("http://image.38.hn/public/attachment/201803/100651/201803151735198462.mp4");
        urlList.add("http://image.38.hn/public/attachment/201803/100651/201803150923220770.mp4");
        urlList.add("http://image.38.hn/public/attachment/201803/100651/201803150922255785.mp4");
        urlList.add("http://image.38.hn/public/attachment/201803/100651/201803150920130302.mp4");
        urlList.add("http://image.38.hn/public/attachment/201803/100651/201803141625005241.mp4");
        urlList.add("http://image.38.hn/public/attachment/201803/100651/201803141624378522.mp4");
        urlList.add("http://image.38.hn/public/attachment/201803/100651/201803131546119319.mp4");

        videoAdapter = new ListVideoAdapter(urlList);
        rvList.setLayoutManager(new LinearLayoutManager(ListActivity.this));
        rvList.setAdapter(videoAdapter);
Copy the code

Adapter here to make a package, you can use native or other packages better, not paste here

  class ListVideoAdapter extends BaseRecAdapter<String.VideoViewHolder> {


        public ListVideoAdapter(List<String> list) {
            super(list);
        }

        @Override
        public void onHolder(VideoViewHolder holder, String bean, int position) {
            holder.mp_video.setUp(bean, JZVideoPlayerStandard.CURRENT_STATE_NORMAL);
            if (position == 0) {
                holder.mp_video.startVideo();
            }
            Glide.with(context).load(bean).into(holder.mp_video.thumbImageView);
            holder.tv_title.setText("The first" + position + "A video");
        }

        @Override
        public VideoViewHolder onCreateHolder(a) {
            return newVideoViewHolder(getViewByRes(R.layout.item_video)); }}public class VideoViewHolder extends BaseRecViewHolder {
        public View rootView;
        public MyVideoPlayer mp_video;
        public TextView tv_title;

        public VideoViewHolder(View rootView) {
            super(rootView);
            this.rootView = rootView;
            this.mp_video = rootView.findViewById(R.id.mp_video);
            this.tv_title = rootView.findViewById(R.id.tv_title); }}Copy the code

Item_video.xml is laid out as follows

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:textSize="18sp" />

    <com.ch.doudemo.widget.MyVideoPlayer
        android:id="@+id/mp_video"
        android:layout_width="match_parent"
        android:layout_height="500dp" />

</LinearLayout>
Copy the code

Here is the use of JiaoZiVideoPlayer, MyVideoPlayer is the company before the project needs to do personalized customization, here again below.

To get to the core of this article, pause/play the video by judging the visible items

/** * Auto play */
    private void autoPlayVideo(RecyclerView recyclerView) {

        if (firstVisibleItem == 0 && lastVisibleItem == 0 && recyclerView.getChildAt(0) != null) {

            MyVideoPlayer videoView = null;
            if(recyclerView ! =null && recyclerView.getChildAt(0) != null) {
                videoView = recyclerView.getChildAt(0).findViewById(R.id.mp_video);
            }
            if(videoView ! =null) {
                if(videoView.currentState == JZVideoPlayer.CURRENT_STATE_NORMAL || videoView.currentState == JZVideoPlayer.CURRENT_STATE_PAUSE) { videoView.startVideo(); }}}for (int i = 0; i <= lastVisibleItem; i++) {
            if (recyclerView == null || recyclerView.getChildAt(i) == null) {
                return;
            }
            MyVideoPlayer
                    videoView = recyclerView.getChildAt(i).findViewById(R.id.mp_video);
            if(videoView ! =null) {

                Rect rect = new Rect();
                // Get the visible coordinates of the view itself, passing the values into the recT object
                videoView.getLocalVisibleRect(rect);
                // Get the height of the video
                int videoHeight = videoView.getHeight();

                if (rect.top <= 100 && rect.bottom >= videoHeight) {
                    if (videoView.currentState == JZVideoPlayer.CURRENT_STATE_NORMAL || videoView.currentState == JZVideoPlayer.CURRENT_STATE_PAUSE) {
                        videoView.startVideo();
                    }
                    return;
                }

                JZVideoPlayer.releaseAllVideos();

            } else{ JZVideoPlayer.releaseAllVideos(); }}}Copy the code

By the way, why use JiaoZiVideoPlayer, because JZVideoPlayer. ReleaseAllVideos (); A single line of code can suspend all players, otherwise it would be a hassle to implement this yourself

At this point, the functionality is probably implemented, so let’s talk about customization.

You need to remove the progress bar and buttons of the original player, click the video to play in full screen, and click again to cancel the full screen.

What I did was I added a layout with zero transparency, overlaid on the player, so that what actually clicked was the layout we had added

Do not change the file name, do not change the file name, do not change the file name, find the relevant layout, set Android :visibility=”gone”, so that the layout in our project will replace the original layout.

The code for jz_layout_standard.xml is as follows

<?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="match_parent"
    android:background="@android:color/black"
    android:descendantFocusability="blocksDescendants">

    <FrameLayout
        android:id="@+id/surface_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </FrameLayout>

    <ImageView
        android:id="@+id/thumb"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:background="# 000000"
        android:scaleType="fitCenter" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone">

        <LinearLayout
            android:id="@+id/layout_bottom"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_alignParentBottom="true"
            android:background="@drawable/jz_bottom_bg"
            android:gravity="center_vertical"
            android:orientation="horizontal"
            android:visibility="invisible">

            <TextView
                android:id="@+id/current"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="14dp"
                android:text="Prefer"
                android:textColor="#ffffff" />

            <SeekBar
                android:id="@+id/bottom_seek_progress"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_weight="1.0"
                android:background="@null"
                android:max="100"
                android:maxHeight="1dp"
                android:minHeight="1dp"
                android:paddingBottom="8dp"
                android:paddingLeft="12dp"
                android:paddingRight="12dp"
                android:paddingTop="8dp"
                android:progressDrawable="@drawable/jz_bottom_seek_progress"
                android:thumb="@drawable/jz_bottom_seek_thumb" />

            <TextView
                android:id="@+id/total"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Prefer"
                android:textColor="#ffffff" />

            <TextView
                android:id="@+id/clarity"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:clickable="true"
                android:paddingLeft="20dp"
                android:text="clarity"
                android:textAlignment="center"
                android:textColor="#ffffff" />

            <ImageView
                android:id="@+id/fullscreen"
                android:layout_width="52.5 dp"
                android:layout_height="fill_parent"
                android:paddingLeft="14dp"
                android:paddingRight="14dp"
                android:scaleType="centerInside"
                android:src="@drawable/jz_enlarge" />
        </LinearLayout>
    </LinearLayout>

    <ProgressBar
        android:id="@+id/bottom_progress"
        style="? android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="1.5 dp"
        android:layout_alignParentBottom="true"
        android:max="100"
        android:progressDrawable="@drawable/jz_bottom_progress" />

    <ImageView
        android:id="@+id/back_tiny"
        android:layout_width="24dp"
        android:layout_height="24dp"
        android:layout_marginLeft="6dp"
        android:layout_marginTop="6dp"
        android:background="@drawable/jz_click_back_tiny_selector"
        android:visibility="gone" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:visibility="gone">

        <RelativeLayout
            android:id="@+id/layout_top"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:background="@drawable/jz_title_bg"
            android:gravity="center_vertical">

            <ImageView
                android:id="@+id/back"
                android:layout_width="23dp"
                android:layout_height="match_parent"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:paddingLeft="12dp"
                android:paddingStart="12dp"
                android:scaleType="centerInside"
                android:src="@drawable/jz_click_back_selector" />


            <TextView
                android:id="@+id/title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginEnd="12dp"
                android:layout_marginLeft="12dp"
                android:layout_marginRight="12dp"
                android:layout_marginStart="12dp"
                android:layout_toEndOf="@+id/back"
                android:layout_toLeftOf="@+id/battery_time_layout"
                android:layout_toRightOf="@+id/back"
                android:ellipsize="end"
                android:maxLines="2"
                android:textColor="#ffffff"
                android:textSize="18sp" />

            <LinearLayout
                android:id="@+id/battery_time_layout"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:layout_marginEnd="14dp"
                android:layout_marginRight="14dp"
                android:gravity="center_vertical"
                android:orientation="vertical">

                <ImageView
                    android:id="@+id/battery_level"
                    android:layout_width="23dp"
                    android:layout_height="10dp"
                    android:layout_gravity="center_horizontal"
                    android:background="@drawable/jz_battery_level_10" />

                <TextView
                    android:id="@+id/video_current_time"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_horizontal"
                    android:gravity="center_vertical"
                    android:maxLines="1"
                    android:textColor="#ffffffff"
                    android:textSize="12.0 sp" />
            </LinearLayout>

        </RelativeLayout>
    </LinearLayout>

    <ProgressBar
        android:id="@+id/loading"
        android:layout_width="@dimen/jz_start_button_w_h_normal"
        android:layout_height="@dimen/jz_start_button_w_h_normal"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:indeterminateDrawable="@drawable/jz_loading"
        android:visibility="invisible" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:visibility="gone">

        <LinearLayout
            android:id="@+id/start_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_gravity="center_vertical">

            <ImageView
                android:id="@+id/start"
                android:layout_width="@dimen/jz_start_button_w_h_normal"
                android:layout_height="@dimen/jz_start_button_w_h_normal"
                android:src="@drawable/jz_click_play_selector" />
        </LinearLayout>

        <TextView
            android:id="@+id/replay_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/start_layout"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="6dp"
            android:text="@string/replay"
            android:textColor="#ffffff"
            android:textSize="12sp"
            android:visibility="invisible" />


        <LinearLayout
            android:id="@+id/retry_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:gravity="center_horizontal"
            android:orientation="vertical">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/video_loading_faild"
                android:textColor="@android:color/white"
                android:textSize="14sp" />

            <TextView
                android:id="@+id/retry_btn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="15dp"
                android:background="@drawable/retry_bg"
                android:paddingBottom="4dp"
                android:paddingLeft="9dp"
                android:paddingRight="9dp"
                android:paddingTop="4dp"
                android:text="@string/click_to_restart"
                android:textColor="@android:color/white"
                android:textSize="14sp" />
        </LinearLayout>
    </LinearLayout>

    <RelativeLayout
        android:id="@+id/rl_touch_help"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:alpha="0"
        android:background="@color/cf0f2f7"></RelativeLayout>

    <LinearLayout
        android:id="@+id/ll_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:padding="15dp"
        android:visibility="gone">

        <ImageView
            android:id="@+id/iv_start"
            android:layout_width="16dp"
            android:layout_height="18dp"
            android:background="@mipmap/stop" />
    </LinearLayout>


</RelativeLayout>

Copy the code

You also need to implement a loop, which is easier, by overriding the onAutoCompletion method and continuing once it’s finished.

 @Override
    public void onAutoCompletion(a) {

        thumbImageView.setVisibility(View.GONE);

        if (currentScreen == SCREEN_WINDOW_FULLSCREEN) {
            onStateAutoComplete();
            setUp((String) getCurrentUrl(), JZVideoPlayer.SCREEN_WINDOW_FULLSCREEN);
        } else {
            super.onAutoCompletion();
            setUp((String) getCurrentUrl(), JZVideoPlayer.CURRENT_STATE_NORMAL);
        }
        // Loop

        startVideo();
    }
Copy the code

At this point, the list play function is done.

Finally, present the complete code.Github

Your recognition is the motivation for me to keep updating my blog. If it is useful, please give me a thumbs-up. Thank you