android recycleView can also be used to display four videos

Recently, the company made a project, which requires that four-way video can be displayed. It would be very troublesome to use layout package. Later, under the leadership of the God, I learned that recycling view can be used,

The specific requirements are as follows

























The specific requirements are as shown in the figure above. Next, recycle view is used to realize this function and directly upload the code

1. Recycleview inheritance class

public class VideoViewContainer extends RecyclerView {
    public VideoViewContainer(Context context) {
        super(context);
    }

    public VideoViewContainer(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public VideoViewContainer(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    private VideoViewRecycleAdapter mVideoViewRecycleAdapter;

    private boolean initAdapter(LinkedHashMap<String, StreamView> users) {
        if (mVideoViewRecycleAdapter == null) {
            mVideoViewRecycleAdapter = new VideoViewRecycleAdapter(getContext(), users);
            return true;
        }
        return false;
    }

    public void initViewContainer(Context context, LinkedHashMap<String, StreamView> streamViewMap) {
/*        ArrayList<StreamView> list = new ArrayList<StreamView>();
        Collection<StreamView> collection = streamViewMap.values();
        Iterator<StreamView> iterator = collection.iterator();
        while (iterator.hasNext()) {
            StreamView value = (StreamView) iterator.next();
            list.add(value);
        }*/
        boolean newCreated = initAdapter(streamViewMap);  //Initialize adapter

        if (!newCreated) {
           mVideoViewRecycleAdapter.init(streamViewMap);  //The main purpose of the method in adapter is to calculate the height of each item
        }

        this.setAdapter(mVideoViewRecycleAdapter);

        int count = streamViewMap.size();  //streamViewMap is the collection with surfaceview passed from activity
        if (count < 2) { // Only local full view or with one peer
            this.setLayoutManager(new LinearLayoutManager(context, RecyclerView.VERTICAL, false));
        } else if (count == 2 || count == 4) {  //Layout when there are two-way or four-way videos
       //     this.setLayoutManager(new GridLayoutManager(context, 2, RecyclerView.VERTICAL, false));
            GridLayoutManager llmv;
            llmv = new GridLayoutManager(context,2, GridLayoutManager.VERTICAL, false);
            this.setLayoutManager(llmv);
        }else if(count == 3){  //Layout when there are three videos
            GridLayoutManager llmv;
            llmv = new GridLayoutManager(context,2, GridLayoutManager.VERTICAL, false);
            llmv.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    //Return value: number of cross columns
                    if (position == 2){
                        return 2;
                    }
                    return 1;
                }
            });
            this.setLayoutManager(llmv);
        }

        mVideoViewRecycleAdapter.notifyDataSetChanged();
    }

The labels are very clear. Let's have a look

2. The following is adapter videoviewrecycleview adapter

public class VideoViewRecycleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    protected LayoutInflater mInflater;
    protected Context mContext;

  public ArrayList<StreamView> mUsers;
    public VideoViewRecycleAdapter(Context context, LinkedHashMap<String, StreamView> users) {
        mContext = context;
        mInflater = ((Activity) context).getLayoutInflater();
        mUsers = new ArrayList<>();
        if(users != null) {
            for (LinkedHashMap.Entry<String, StreamView> entry : users.entrySet()) {
                mUsers.add(entry.getValue());
            }
        }
    }

    protected int mItemWidth = 0;
    protected int mItemHeight = 0;

    /**
     * The main method of implementation is to initialize the layout
     * @param parent
     * @param viewType
     * @return
     */
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Log.d("VideoViewAdapter", "--------------------onCreateViewHolder " + viewType);

        View v = mInflater.inflate(R.layout.item_recycle_video, parent, false);
        Log.d("VideoViewAdapter", "--------------------onCreateViewHolder mInflaterend");

        Log.d("VideoViewAdapter", "--------------------onCreateViewHolder container end");
        v.getLayoutParams().width = mItemWidth;
        v.getLayoutParams().height = mItemHeight;
        return new VideoHolder(v);
    }

    /**
     * The main task is to check whether the passed view has a parent class. If the parent class is not deleted, an error will be reported in addview
     * @param view
     */
    protected final void stripSurfaceView(View view) {
        if(view == null){
            return;
        }
        ViewParent parent = view.getParent();
        if (parent != null) {
            ((ViewGroup) parent).removeView(view);
        }
    }

    /**
     * Calculate the height of the item in the case of different videos
     * @param users Here, the collection streamview with surface view inherits the surface view
     */
    public void init(LinkedHashMap<String, StreamView> users){

        int beforeCount = mUsers.size();
        mUsers.clear();
        for (LinkedHashMap.Entry<String, StreamView> entry : users.entrySet()) {
            mUsers.add(entry.getValue());
        }
            WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics outMetrics = new DisplayMetrics();
            windowManager.getDefaultDisplay().getMetrics(outMetrics);

            int count = mUsers.size();
            int DividerX = 1;
            int DividerY = 1;
            if (count > 1) {
                DividerX = 2;
                DividerY = 2;
            }

            mItemWidth = outMetrics.widthPixels / DividerX;
            mItemHeight = outMetrics.heightPixels / DividerY;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        VideoHolder myHolder = ((VideoHolder) holder);

        final StreamView user = mUsers.get(position);

        V2Log.d("VideoViewAdapter","-----------------------------onBindViewHolder " + position + " " + user + " " + myHolder + " " + myHolder.itemView);
        LinearLayout holderView = (LinearLayout) myHolder.itemView;  //Get the layout of each item through holder
        FrameLayout container;
        container = (FrameLayout) holderView.findViewById(R.id.video_view_container);
        if(mUsers.size()==2){   //Position display and display size of layout when there are two videos
            LinearLayout.LayoutParams layoutParams
           = new LinearLayout.LayoutParams(mItemWidth, mItemHeight);
                //    (FrameLayout.LayoutParams) holderView.getLayoutParams();
           layoutParams.setMargins(0, mItemHeight/2,0 , mItemHeight/2);
            holderView.setLayoutParams(layoutParams);
        }else if(position==2 && mUsers.size()==3){  //Position display and display size of the third layout when there are three videos
            Log.e("VideoViewAdapter","-----------------------------onBindViewHolder " + position + " " + user + " " + myHolder + " " + myHolder.itemView);
            LinearLayout.LayoutParams layoutParams
                    = new LinearLayout.LayoutParams(mItemWidth, mItemHeight);
               // (FrameLayout.LayoutParams) holderView.getLayoutParams();
            layoutParams.setMargins(mItemWidth/2, 0,mItemWidth/2 , 0);
            holderView.setLayoutParams(layoutParams);
        }

        if (container.getChildCount() == 0 && user!=null) {  //When it is a one-way video, full screen display
            stripSurfaceView(user);
            container.addView(user, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        }
    }

    @Override
    public int getItemCount() {
        Log.d("VideoViewAdapter", "getItemCount " + mUsers.size());
        int sizeLimit = mUsers.size();
        if (sizeLimit >= 4) {
            sizeLimit = 4;
        }
        return sizeLimit;
    }

}
The notes are clear,

3. Streamview is the encapsulation class of surfaceview

public class StreamView extends RelativeLayout {
    TextView textView,textViewName;
    SurfaceView surfaceView;
    boolean isLocalStream;

    public long getStreamId() {
        return streamId;
    }

    public long getUserId() {
        return userId;
    }

    long streamId;
    long userId;
    public StreamView(@NonNull Context context, SurfaceView view, boolean local,long streamId, long userId) {
        super(context);
        isLocalStream = local;
        this.streamId = streamId;
        this.userId = userId;
        textView = new TextView(context);
        textViewName = new TextView(context);
        surfaceView = view;
        initSurfaceView();

    }

    public StreamView(@NonNull Context context, @Nullable AttributeSet attrs, SurfaceView view, boolean local,long streamId, long userId) {
        super(context, attrs);
        this.addView(view);
        isLocalStream = local;
        this.streamId = streamId;
        this.userId = userId;
        surfaceView = view;
        textView = new TextView(context);
        textViewName = new TextView(context);
        initSurfaceView();
    }

    public StreamView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr, SurfaceView view, boolean local,long streamId, long userId) {
        super(context, attrs, defStyleAttr);
        this.addView(view);
        isLocalStream = local;
        this.streamId = streamId;
        this.userId = userId;
        surfaceView = view;
        textView = new TextView(context);
        textViewName = new TextView(context);
        initSurfaceView();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public StreamView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, SurfaceView view, boolean local,long streamId, long userId) {
        super(context, attrs, defStyleAttr, defStyleRes);
        isLocalStream = local;
        this.streamId = streamId;
        this.userId = userId;
        surfaceView = view;
        textView = new TextView(context);
        textViewName = new TextView(context);
        initSurfaceView();
    }

    public void initSurfaceView(){
        LayoutParams layoutParams
           =new LayoutParams(LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
        if(surfaceView!= null) {
            surfaceView.setLayoutParams(layoutParams);
        }
        this.addView(surfaceView);
        LayoutParams layoutParams2
                =new LayoutParams(LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            layoutParams2.setMarginEnd(10);
        }
        layoutParams2.rightMargin = 10;
        layoutParams2.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
    //    layoutParams.addRule(RelativeLayout.);
        textView.setLayoutParams(layoutParams2);
        this.addView(textView);

        LayoutParams layoutParams1 = new LayoutParams(layoutParams.WRAP_CONTENT,layoutParams.WRAP_CONTENT);
        layoutParams1.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        layoutParams1.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        layoutParams1.rightMargin = 10;
        textViewName.setLayoutParams(layoutParams1);
        this.addView(textViewName);
    }
Surface view textview is added to display names

4.adapter layout

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="@drawable/video_view_border"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">
    <FrameLayout
        android:layout_margin="2dp"
        android:layout_marginBottom="2dp"
        android:layout_marginTop="2dp"
        android:layout_marginLeft="2dp"
        android:layout_marginEnd="2dp"
        android:layout_marginRight="2dp"
        android:gravity="center"
        android:id="@+id/video_view_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        >

    </FrameLayout>
</LinearLayout>


Finally, through the above main code, you can complete the requirements pull as shown in the figure above, hoping to help the partners




Tags: Android SurfaceView

Posted on Sat, 02 May 2020 03:56:34 -0400 by wdsmith