Android仿微信视频聊天本地与远程切换功能

一、xml布局

复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/coordinatorLayout"
    android:layout_width="@dimen/dp_640"
    android:layout_height="@dimen/dp_400"
    android:background="@color/pageBgColor"
    android:orientation="vertical">

    <!--  视频预览 -->
    <csu.xiaoya.robotApp.ui.activity.homepage.familydct.bean.DraggableTextureView
        android:id="@+id/preview"
        android:layout_width="@dimen/dp_640"
        android:layout_height="@dimen/dp_400"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintLeft_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!--  远程视频 -->
    <csu.xiaoya.robotApp.ui.activity.homepage.familydct.bean.DraggableTextureView
        android:id="@+id/remoteUserView"
        android:layout_width="150dp"
        android:layout_height="180dp"
        android:layout_marginTop="30dp"
        android:layout_marginRight="30dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintLeft_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/imHead"
        android:layout_width="@dimen/dp_120"
        android:layout_height="@dimen/dp_120"
        android:layout_gravity="center"
        android:layout_marginBottom="@dimen/dp_100"
        android:scaleType="centerCrop"
        android:src="@mipmap/doctor_head"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <ImageView
        android:id="@+id/changeVideoWindows"
        android:layout_width="@dimen/dp_30"
        android:layout_height="@dimen/dp_30"
        android:layout_marginLeft="@dimen/dp_30"
        android:layout_marginTop="@dimen/dp_30"
        android:background="@drawable/change_windows"
        android:src="@mipmap/video_windows_change"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

二、切换代码

复制代码
 /**
     * 通话大小
     * 窗口切换
     */
    private boolean isLocalVideoSmallState = true;

    private void switchWindowMode(VideoChatDialog videoChatDialog, boolean isLocalVideoSmall) {
        ConstraintLayout constraintLayout = videoChatDialog.findViewById(R.id.coordinatorLayout);
        TextureView localVideoTextureView = videoChatDialog.findViewById(R.id.preview);
        TextureView remoteVideoTextureView = videoChatDialog.findViewById(R.id.remoteUserView);
    
        ImageView changeVideoWindows = videoChatDialog.findViewById(R.id.changeVideoWindows);

        ConstraintSet constraintSet = new ConstraintSet();
        constraintSet.clone(constraintLayout);
        if (isLocalVideoSmall) {

            constraintLayout.removeView(localVideoTextureView);
            constraintLayout.removeView(remoteVideoTextureView);
    
            constraintLayout.removeView(changeVideoWindows);

            constraintLayout.addView(remoteVideoTextureView);
            constraintLayout.addView(localVideoTextureView);
  
            constraintLayout.addView(changeVideoWindows);

            // 远程端全屏模式
            remoteVideoTextureView.setEnabled(false);
            constraintSet.clear(remoteVideoTextureView.getId());
            constraintSet.connect(remoteVideoTextureView.getId(), ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, 0);
            constraintSet.connect(remoteVideoTextureView.getId(), ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END, 0);
            constraintSet.connect(remoteVideoTextureView.getId(), ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT, 0);

            constraintSet.constrainWidth(remoteVideoTextureView.getId(), 1280);
            constraintSet.constrainHeight(remoteVideoTextureView.getId(), 800);

            // 本地小窗口
            localVideoTextureView.setEnabled(true);
            constraintSet.clear(localVideoTextureView.getId());

            constraintSet.connect(localVideoTextureView.getId(), ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, 30);
            constraintSet.connect(localVideoTextureView.getId(), ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END, 0);
            constraintSet.connect(localVideoTextureView.getId(), ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT, 30);

            constraintSet.constrainWidth(localVideoTextureView.getId(), 300); // 设置小窗口的宽度
            constraintSet.constrainHeight(localVideoTextureView.getId(), 200);

            isLocalVideoSmallState = false;

        } else {

            constraintLayout.removeView(remoteVideoTextureView);
            constraintLayout.removeView(localVideoTextureView);
      
            constraintLayout.removeView(changeVideoWindows);

            constraintLayout.addView(localVideoTextureView);
            constraintLayout.addView(remoteVideoTextureView);
          
            constraintLayout.addView(changeVideoWindows);

            // 本地 全屏模式
            localVideoTextureView.setEnabled(false);
            constraintSet.clear(localVideoTextureView.getId());

            constraintSet.connect(localVideoTextureView.getId(), ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, 0);
            constraintSet.connect(localVideoTextureView.getId(), ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END, 0);
            constraintSet.connect(localVideoTextureView.getId(), ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT, 0);

            constraintSet.constrainWidth(localVideoTextureView.getId(), 1280);
            constraintSet.constrainHeight(localVideoTextureView.getId(), 800);

            // 远程 小窗口
            remoteVideoTextureView.setEnabled(true);
            constraintSet.clear(remoteVideoTextureView.getId());

            constraintSet.connect(remoteVideoTextureView.getId(), ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, 30);
            constraintSet.connect(remoteVideoTextureView.getId(), ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END, 0);
            constraintSet.connect(remoteVideoTextureView.getId(), ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT, 30);

            constraintSet.constrainWidth(remoteVideoTextureView.getId(), 300); // 设置小窗口的宽度
            constraintSet.constrainHeight(remoteVideoTextureView.getId(), 200);

            isLocalVideoSmallState = true;
        }

        constraintSet.applyTo(constraintLayout);

    }

三、自定义可拖拽TextureView

复制代码
/**
 * 自定义可拖动
 * TextureView
 */

public class DraggableTextureView extends TextureView {

    private float lastX;
    private float lastY;
    private boolean isDragging;

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

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


    public DraggableTextureView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }


    private void init() {
        setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        lastX = event.getRawX();
                        lastY = event.getRawY();
                        isDragging = true;
                        break;
                    case MotionEvent.ACTION_MOVE:
                        if (isDragging) {
                            float dx = event.getRawX() - lastX;
                            float dy = event.getRawY() - lastY;
                            int newLeft = (int) (v.getLeft() + dx);
                            int newTop = (int) (v.getTop() + dy);
                            int newRight = (int) (v.getRight() + dx);
                            int newBottom = (int) (v.getBottom() + dy);
                            v.layout(newLeft, newTop, newRight, newBottom);
                            lastX = event.getRawX();
                            lastY = event.getRawY();
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                    case MotionEvent.ACTION_CANCEL:
                        isDragging = false;
                        break;
                }
                return true;
            }
        });
    }

}
相关推荐
杉氧2 小时前
状态管理变迁史:为什么我们放弃了 Redux 选择 Zustand?
android·前端·react native
三少爷的鞋6 小时前
别再靠 Code Review 守底线:我做了一个静态分析项目 RedLine
android
y = xⁿ14 小时前
DeepSeek Harness 学习日记:关于Agent接口,工具调用的底层实现
android·java·学习
2601_9620664916 小时前
【Sql Server】Update中的From语句,以及常见更新操作方式
android·java·数据库
用户693717500138421 小时前
曾经安卓开发人手一个的 EventBus,为什么现在没人爱用了?
android·android studio
九皇叔叔1 天前
MySQL ORDER BY 性能优化详解:Using filesort、联合索引、ASC/DESC 与覆盖索引
android·adb
OriginCoding1 天前
用 AI Agent 协作完成一个 Android TOTP 应用:从需求边界到 v1.0.0
android·ai编程
杉氧1 天前
React 灵魂:深入剖析 Hooks 与副作用(Side Effects)陷阱
android·前端·react native
又见情义1 天前
RK3568 + RTL8211F 网络唤醒(WOL)功能适配全记录
android·网络·驱动开发
用户0934077735141 天前
HarmonyOS WPS Open SDK 实践:registerApp 鉴权与就绪门禁
android·typescript·harmonyos