【Android】【需求实现记录】构建一个约束布局在横竖屏情况喜爱和ImageView的实际展示的图片大小完全重合覆盖

文章讲述了在Android开发中如何处理textureView在横竖屏切换时保持与图片背景相对位置一致的问题。关键在于获取图片实际展示的大小和缩放比例,通过调整约束布局参数来适应屏幕变化。代码示例展示了如何在onSizeChanged和onConfigurationChanged方法中动态调整布局。
摘要由CSDN通过智能技术生成

背景

现在有一个需求:无论横竖屏模式,textureView 的相对位置应该和图片背景保持一致。
如图所示:
在这里插入图片描述

产品要求图片居中不拉伸,保证图片的背景效果 & 可以接受黑边。

那么这最外层的约束布局中的bg就不能直接引用 android:background来设置图片背景,因为就呈现拉伸的状态。
那么就得使用imageView来实现并设置scaleType为centerInside就可以满足产品需求。
但是
无论横竖屏模式,textureView 的相对位置应该和图片背景保持一致 这个需求就得知道当前手机实际展示图片大小。

这是本次需求的重难点:
获取当前实际展示的图片大小并构建一个子约束布局来处理视频流(即上图的人物)。

解决

核心代码如下:


    /**
     * 该方法保障subLayout 和 imageView
     * 实际展示的图片大小完全重合
     * 以保证横竖屏切换的情况下都是完全贴合的
     *
     * @param imageView imageview对象
     * @param subLayout 约束布局
     */
    private void makeConstraintLayoutSuitable(ImageView imageView, ConstraintLayout subLayout) {
        // 获取ImageView的Drawable对象
        Drawable drawable = imageView.getDrawable();

        // 获取Drawable的大小
        int drawableWidth = drawable.getBounds().width();
        int drawableHeight = drawable.getBounds().height();

        //获得ImageView中Image的变换矩阵
        Matrix m = imageView.getImageMatrix();
        float[] values = new float[10];
        m.getValues(values);

        //Image在绘制过程中的变换矩阵,从中获得x和y方向的缩放系数
        float sx = values[0];
        float sy = values[4];

        // 刷新约束layout 布局大小
        ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) subLayout.getLayoutParams();
        //计算Image在屏幕上实际绘制的宽高
        layoutParams.width  = (int) (drawableWidth * sx);
        layoutParams.height = (int) (drawableHeight * sy);

        // 当前的图片的展示宽高 数据刷新
        realBgWidth = layoutParams.width;
        realBgHeight = layoutParams.height;

        subLayout.setLayoutParams(layoutParams);
    }

但是调用的时机要非常准确,,那么我们可以在 RoomMiddleView 中重写 onSizeChanged 方法,在横竖屏切换后获取到实际展示的 imageView 中的大小和缩放比例,然后根据这些信息重新设置 subLayout 的大小和约束条件。具体实现可以参考以下代码:来保证横竖屏的时候调用时机不会太早,使用旧的ImageView(即没有横屏或者竖屏后)的大小数据来加工的。

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    makeConstraintLayoutSuitable(ivRoomBg, subLayout);
}

完整代码:

public class RoomMiddleView extends ConstraintLayout {

    // textureView 的数据容器:根据房间配置数据来保证长度
    private List<TextureView> textureViewList = new ArrayList<>();

    public List<TextureView> getTextureViewList() {
        return textureViewList;
    }

    public RoomMiddleView(@NonNull Context context) {
        super(context);
    }

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

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

    private ImageView ivRoomBg;

    // 子约束布局用来保证 textureView的
    private ConstraintLayout subLayout;

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // TODO: 2023/4/28  在横竖屏的时候需要考虑不同的texture的布局
    }

    // 当前的图片背景bg的展示宽高
    int realBgWidth;
    int realBgHeight;

    public void init(RoomInternalItem roomItem) {
        LayoutInflater.from(getContext()).inflate(R.layout.fs_room_middle, this);
        ivRoomBg = findViewById(R.id.iv_room_bg);


        RoomTypeConfig config = roomItem.getSubItem().getConfig();
        // 背景更换
        ivRoomBg.setImageResource(roomItem.getSubItem().getDrawable());

        subLayout = findViewById(R.id.sub_layout);

        // 保证初始化完成之后才调用,这样获取到的imageview 的宽高 数据就不会是0
        post(() -> {
            makeConstraintLayoutSuitable(ivRoomBg,subLayout);
            boolean isLandScape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
            refreshTextureViews(config,subLayout,isLandScape);
        });

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        /*
         *  重要!!!
         *  无论是横竖屏情况下都能保证sub子约束布局 和 图片实际展示位置的大小
         *  完成覆盖重合
         */
        post(() -> makeConstraintLayoutSuitable(ivRoomBg,subLayout));
    }


    private void refreshTextureViews(RoomTypeConfig config, ConstraintLayout subLayout,boolean isLandscape) {
        // 前一个下标 TextureView
        TextureView preTexture = null;

        //TextureView 的初始化
        for(int i = 0; i< config.getMaxMemberCount(); i++){
            TextureView textureView = new TextureView(getContext());
            // 默认 设置透明 方便直接供SDK使用
            textureView.setOpaque(false);
            // 数据容器添加
            textureViewList.add(textureView);
            // 添加指定的id
            textureView.setId(View.generateViewId());
            // 添加到约束布局的视图里面
            subLayout.addView(textureView);

            // 布局管理
            ConstraintSet constraintSet = new ConstraintSet();
            constraintSet.clone(subLayout);

            int textureViewWidth =  100;
            int textureViewHeight = 100;
            // TODO: 2023/4/13 算法研究textureView的布局待定

            // 这个TextureView的宽高
            constraintSet.constrainWidth(textureView.getId(), textureViewWidth);
            constraintSet.constrainHeight(textureView.getId(), textureViewHeight);
            // 设置约束效果
            constraintSet.connect(textureView.getId(), ConstraintSet.TOP, subLayout.getId(),ConstraintSet.TOP);
            constraintSet.connect(textureView.getId(), ConstraintSet.BOTTOM, subLayout.getId(), ConstraintSet.BOTTOM);
            if(i==0){
                constraintSet.connect(textureView.getId(), ConstraintSet.START, subLayout.getId(),ConstraintSet.START);
            }else {
                constraintSet.connect(textureView.getId(), ConstraintSet.START, preTexture.getId(), ConstraintSet.END);
            }
            // TODO: 2023/4/16 还得考虑横竖屏的切换导致的View约束效果
            constraintSet.applyTo(subLayout);// 将修改后的约束条件应用到布局中
            preTexture = textureView;

        }
    }

    /**
     * 该方法保障subLayout 和 imageView
     * 实际展示的图片大小完全重合
     * 以保证横竖屏切换的情况下都是完全贴合的
     *
     * @param imageView imageview对象
     * @param subLayout 约束布局
     */
    private void makeConstraintLayoutSuitable(ImageView imageView, ConstraintLayout subLayout) {
        // 获取ImageView的Drawable对象
        Drawable drawable = imageView.getDrawable();

        // 获取Drawable的大小
        int drawableWidth = drawable.getBounds().width();
        int drawableHeight = drawable.getBounds().height();

        //获得ImageView中Image的变换矩阵
        Matrix m = imageView.getImageMatrix();
        float[] values = new float[10];
        m.getValues(values);

        //Image在绘制过程中的变换矩阵,从中获得x和y方向的缩放系数
        float sx = values[0];
        float sy = values[4];

        // 刷新约束layout 布局大小
        ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) subLayout.getLayoutParams();
        //计算Image在屏幕上实际绘制的宽高
        layoutParams.width  = (int) (drawableWidth * sx);
        layoutParams.height = (int) (drawableHeight * sy);

        // 当前的图片的展示宽高 数据刷新
        realBgWidth = layoutParams.width;
        realBgHeight = layoutParams.height;

        subLayout.setLayoutParams(layoutParams);
    }
}

视图文件:

<?xml version="1.0" encoding="utf-8"?>
<!-- fs 房间内的 中间显示框-->
<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/layout"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/fs_common_black">
    <!--图片布局 竖屏:centerInside  横屏:fixXY  -->
    <ImageView
        android:id="@+id/iv_room_bg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="centerInside"
        android:src="@drawable/fs_pic_study_horizontal"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/sub_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值