Android 仿照微信查看大图

本文介绍了一个在Android中实现的图片画廊弹窗,支持查看大图和拍照功能。该弹窗使用`DialogFragment`,`ViewPager2`和自定义适配器来展示图片列表,同时提供了重拍和删除图片的选项。图片上传逻辑包括获取Token、上传图片和处理上传成功后的回调。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果图如下:

在这里插入图片描述

图片

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

代码如下


import android.annotation.SuppressLint
import android.content.Context
import android.content.DialogInterface
import android.graphics.*
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import android.view.*
import android.widget.ImageView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.alibaba.fastjson.JSON
import com.google.gson.Gson
import com.lzy.okgo.model.Response
import kotlinx.android.synthetic.main.hybrid_activity_image_gallery.*
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
import kotlin.math.abs

/**
 * 支持画廊式查看大图的弹窗
 */
class ImageGalleryDialog1 : DialogFragment() {

    companion object {

        const val END_ITEM_VIEW_TYPE = 0
        const val ITEM_VIEW_TYPE = 1

        /**
         * @param dataSourceJson H5传递过来的json
         */
        fun newInstance(dataSourceJson: String): ImageGalleryDialog {
            val args = Bundle()
            args.putString("imageData", dataSourceJson)

            val fragment = ImageGalleryDialog()
            fragment.arguments = args
            return fragment
        }
    }


    /**
     * 源数据
     */
    private var dataSource: GalleryImageActivityBean? = null

    private var adapter: ImageGalleryAdapter? = null

    private var pageSize: Int = 0

    private var pageIndex: Int = 0

    private val selfTag = "ImageGalleryDialog"

    /**
     * 如果是重拍,这个值会不等于-1
     */
    private var reviewPhotoPosition = -1

    var resultJson = ""

    var onImageDialogDismissListener: OnImageDialogDismissListener? = null

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.hybrid_activity_image_gallery, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initData()
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
        super.onActivityCreated(savedInstanceState)

        dialog?.window?.setBackgroundDrawable(ColorDrawable(0x00000000))
        dialog?.window?.setLayout(
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.MATCH_PARENT
        )
    }

    private fun initData() {
        val imageDataJson = arguments?.getString("imageData", "")
        kotlin.runCatching {
            dataSource = Gson().fromJson(imageDataJson, GalleryImageActivityBean::class.java)
            pageSize = dataSource?.imageList?.size?: 0
            pageIndex =
                if (dataSource?.currentPosition?: 0 >= pageSize) 0 else dataSource?.currentPosition
                    ?: 0
        }.onSuccess {
            initWidget()
        }.onFailure {
            ToastUtil.showToast("数据错误!")
            dismissAllowingStateLoss()
        }
    }

    /**
     * 初始化控件
     */
    @SuppressLint("SetTextI18n")
    private fun initWidget() {
        adapter = ImageGalleryAdapter(context, dataSource?.imageList, dataSource?.isReview)
        imagePager.offscreenPageLimit = 2
        imagePager.setPageTransformer(ImageGalleryZoomOutPageTransformer())
        imagePager.adapter = adapter
        tvIndex.text = "${pageIndex}/${adapter?.itemCount}"
        imagePager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                super.onPageSelected(position)
                pageIndex = position
                tvIndex.text = "${pageIndex + 1}/${adapter?.itemCount}"
                if (adapter?.getItemViewType(position) != ITEM_VIEW_TYPE || dataSource?.isReview == false) {
                    ivReset.visibility = View.GONE
                    ivDeleted.visibility = View.GONE
                }else {
                    ivReset.visibility = View.VISIBLE
                    ivDeleted.visibility = View.VISIBLE
                }

                if ((imagePager?.getChildAt(0) is RecyclerView)) {
                    if ((imagePager?.getChildAt(0) as RecyclerView).findViewHolderForAdapterPosition(adapter?.selectedPosition?:0) is ImageGalleryViewHolder) {
                        val oldHolder = (imagePager?.getChildAt(0) as RecyclerView).findViewHolderForAdapterPosition(adapter?.selectedPosition?:0) as ImageGalleryViewHolder
                        oldHolder.itemRootView?.isSelected = false
                    }
                    if ((imagePager?.getChildAt(0) as RecyclerView).findViewHolderForAdapterPosition(position) is ImageGalleryViewHolder) {
                        val newSelectedHolder = (imagePager?.getChildAt(0) as RecyclerView).findViewHolderForAdapterPosition(position) as ImageGalleryViewHolder
                        newSelectedHolder.itemRootView?.isSelected = true
                    }
                }
                adapter?.selectedPosition = position
            }
        })

        adapter?.onImageGalleryAddPhotoClickListener = object : OnImageGalleryAddPhotoClickListener {
                override fun onAddPhotoItemClick() {
                    if (dataSource?.imageList?.size ?: 0 < 9) {
                        takePhoto()
                    }
                }
            }

        ivReset.click {
            // 重拍
            reviewPhotoPosition = imagePager.currentItem
            takePhoto()
        }

        ivDeleted.click {
            // 删除照片
            if (adapter?.getItemViewType(imagePager.currentItem) == ITEM_VIEW_TYPE) {
                val currentPosition = imagePager.currentItem
                dataSource?.imageList?.removeAt(currentPosition)
                adapter?.notifyItemRemoved(currentPosition)
                imagePager?.post {
                    imagePager?.requestTransform()
                }
            }
        }

        imageGalleryRootView.click {
            // 点击空白区域关闭
            dismiss()
        }
    }

    override fun onDismiss(dialog: DialogInterface) {
        super.onDismiss(dialog)
        if (dataSource?.isReview == true) {
            resultJson = Gson().toJson(dataSource)
        }
        onImageDialogDismissListener?.onDismiss(resultJson)
        dismiss()
    }

    /**
     * 去拍照
     */
    private fun takePhoto() {
        context?.let { context ->
            val isHuar = TextUtils.equals("KNC", Build.MANUFACTURER) || TextUtils.equals("X1", Build.MODEL)
            var camera_type = SharedPreferenceUtil.getIntValueFromSP("hbdPicture" , CAMERA_TYPE , -1)
            camera_type = if(isHuar) { // 华瑞安机器
                if(camera_type == -1) AXXCameraActivity.CAMERA_TYPE_FRONT else camera_type
            } else {
                if(camera_type == -1) AXXCameraActivity.CAMERA_TYPE_BACK else camera_type
            }
            val cameraWrapper = AXXAlbumCamera(context).image().cameraType(camera_type)
            cameraWrapper
                .onResult {
                    showLoadingDialog()
                    getToken(filePath = it)
                }
                .onCancel {
                }
                .start()
        }
    }

    private fun showLoadingDialog() {
        if (context is BaseActivity) {
            (context as BaseActivity).showLoadingProgressDialog()
        }
    }

    private fun hideLoadingDialog() {
        if (context is BaseActivity) {
            (context as BaseActivity).dismissLoadingProgressDialog()
        }
    }

    /**
     * 图片上传成功了
     */
    private fun onUploadSuccess(itemBean: GalleryImageItemBean) {
        if (reviewPhotoPosition != -1) {
            // 重拍的
            dataSource?.imageList?.set(reviewPhotoPosition, itemBean)
            adapter?.notifyItemChanged(reviewPhotoPosition)
            reviewPhotoPosition = -1
        }else {
            // 新增的
            dataSource?.imageList?.add(itemBean)
            if (dataSource?.imageList?.size?:0 >= 9) {
                adapter?.notifyItemRangeChanged(0, 9)
                imagePager?.post {
                    imagePager?.requestTransform()
                }
            }else {
                adapter?.notifyItemInserted((dataSource?.imageList?.size?:0) - 1)
            }
        }
    }

    /**↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓下面这一坨是拍照上传的逻辑↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/

    // 摄像头类型(2 前 or  1 后)
    private val CAMERA_TYPE = "camera_type"

    /**
     * 获取Token
     */
    private fun getToken(filePath: String) {
        GGGGRequest.startRequest(
            SDKConfig.getBaseUrl() + "api/common/storageToken",
            GGGGRequest.GET,
            HashMap<String, String>(),
            object : GGGGGStringCallback() {
                override fun onResponseSuccess1(response: Response<*>?, code: Int, result: String) {
                    ReportLog.method(
                        selfTag,
                        "takeJzxPhoto",
                        "获取Token onResponseSuccess: $code result: $result"
                    )
                    val resultJson = JSON.parseObject(result)
                    val body = resultJson.getJSONObject("body")
                    val token = body.getString("token")
                    upload(token, filePath)
                }

                override fun onResponseError1(response: Response<*>?, code: Int, message: String?) {
                    ReportLog.method(
                        selfTag,
                        "takeJzxPhoto",
                        "获取Token onResponseError: $code result: $result"
                    )
                    hideLoadingDialog()
                }
            })
    }

    /**
     * 上传图片
     *  if (isHuar) convertBitmap(BitmapUtil.getBitmapFormPath(filePath)) else
     */
    private fun upload(token: String, filePath: String) {
        val isHuar =
            TextUtils.equals("KNC", Build.MANUFACTURER) || TextUtils.equals("X1", Build.MODEL)
        val originalBitmap = getBitmapFormPath(filePath , isHuar)
        if (originalBitmap?.bitmap == null) {
            ReportLog.method(selfTag , "takeJzxPhoto" ,  "originalBitmap == null")
            hideLoadingDialog()
            return
        }
        // 写入存储,用于记录是前摄还是后摄
        SharedPreferenceUtil.setIntDataIntoSP("", CAMERA_TYPE , originalBitmap?.source)
        val convertBitmap = if (originalBitmap?.source == AXXCameraActivity.CAMERA_TYPE_FRONT) {
            convertBitmap(originalBitmap?.bitmap!!)
        } else {
            originalBitmap.bitmap
        }
        val bitmapToBase64 = BitmapUtil.bitmapToBase64(convertBitmap)
        Upload.upload(
            0,
            token,
            true,
            bitmapToBase64,
            "${System.currentTimeMillis()}.jpg",
            false,
            object : Upload.UploadListener {
                override fun uploadSuccess(vararg p0: String?) {
                    deletePath(filePath)
                    val key = p0[0]
                    val url = p0[1] ?: ""
                    ReportLog.method(selfTag, "takeJzxPhoto", "图片上传 uploadSuccess: $key : $url")
                    onUploadSuccess(GalleryImageItemBean(url, key))
                    hideLoadingDialog()
                }

                override fun uploadError() {
                    ReportLog.method(selfTag, "takeJzxPhoto", "图片上传失败")
                    hideLoadingDialog()
                }
            })
    }

    /**
     * 镜像转换
     */
    private fun convertBitmap(srcBitmap: Bitmap): Bitmap? {
        val width = srcBitmap.width
        val height = srcBitmap.height
        val canvas = Canvas()
        val matrix = Matrix()
        matrix.postScale(-1f, 1f)
        val newBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, width, height, matrix, true)
        canvas.drawBitmap(
            newBitmap,
            Rect(0, 0, width, height),
            Rect(0, 0, width, height), null
        )
        return newBitmap
    }

    /**
     * 删除文件
     */
    private fun deletePath(filePathName: String): Boolean {
        if (TextUtils.isEmpty(filePathName)) return false
        val file = File(filePathName)
        if (file.exists() && file.isFile) {
            if (file.delete()) {
                return true
            }
        }
        return false
    }
 /**
     * 通过图片判断前摄还是后摄
     */
    data class BitmapEntity(
        var bitmap: Bitmap? = null,
        var source: Int = 0
    )
    /**
     * 从文件路径中读取Bitmap
     */
    @Throws(IOException::class)
    fun getBitmapFormPath(path: String? , isHuar: Boolean) {
        val bitmapEntity = BitmapEntity()
        var input: InputStream = FileInputStream(File(path))
        val onlyBoundsOptions = BitmapFactory.Options()
        onlyBoundsOptions.inJustDecodeBounds = true
        onlyBoundsOptions.inDither = true
        onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888
        BitmapFactory.decodeStream(input, null as Rect?, onlyBoundsOptions)
        input.close()
        val originalWidth = onlyBoundsOptions.outWidth
        val originalHeight = onlyBoundsOptions.outHeight
        if(isHuar) {
            // 通过分辨率判断是不是后摄
            if(originalWidth == 4096
                || originalHeight == 4096) {
                bitmapEntity.source = AXXCameraActivity.CAMERA_TYPE_BACK
            } else {
                bitmapEntity.source = AXXCameraActivity.CAMERA_TYPE_FRONT
            }
        } else {
            bitmapEntity.source = -1 // 无记录
        }
        return if (originalWidth != -1 && originalHeight != -1) {
            var hh = 720.0f
            var ww = 1080.0f
            if(originalWidth < originalHeight) {
                hh = 1080.0f
                ww = 720.0f
            }
            var be = 1
            if (originalWidth > originalHeight && originalWidth.toFloat() > ww) {
                be = (originalWidth.toFloat() / ww).toInt()
            } else if (originalWidth < originalHeight && originalHeight.toFloat() > hh) {
                be = (originalHeight.toFloat() / hh).toInt()
            }
            if (be <= 0) {
                be = 1
            }
            val bitmapOptions = BitmapFactory.Options()
            bitmapOptions.inSampleSize = be
            bitmapOptions.inDither = true
            bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888
            input = FileInputStream(File(path))
            val bitmap = BitmapFactory.decodeStream(input, null as Rect?, bitmapOptions)
            input.close()
            bitmapEntity.bitmap = bitmap
            bitmapEntity
        } else {
            bitmapEntity
        }
    }

    /**↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑上面这一坨是拍照上传的逻辑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑*/

}

/**
 * 图片列表的适配器
 */
class ImageGalleryAdapter1(
    var context: Context?,
    var list: ArrayList<GalleryImageItemBean>?,
    var isReview: Boolean? = true,
    var onImageGalleryAddPhotoClickListener: OnImageGalleryAddPhotoClickListener? = null
) : RecyclerView.Adapter<ImageGalleryViewHolder>() {

    var selectedPosition = 0

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageGalleryViewHolder {
        if (!isEndItemView(viewType)) {
            return ImageGalleryViewHolder(
                LayoutInflater.from(parent.context)
                    .inflate(R.layout.hybrid_item_image_gallery, parent, false)
            )
        }
        return ImageGalleryViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.hybrid_item_image_gallery_photograph, parent, false)
        )
    }

    override fun onBindViewHolder(holder: ImageGalleryViewHolder, position: Int) {
        if (!isEndItemView(getItemViewType(position))) {
            list?.get(position)?.imgUrl?.apply {
                holder.ivPhoto?.loadImageByUrl(this)
            }
        } else {
            holder.itemRootView?.click {
                onImageGalleryAddPhotoClickListener?.onAddPhotoItemClick()
            }
        }
    }

    override fun getItemCount(): Int {
        if (list?.size ?: 0 >= 9) {
            return 9
        }
        return if(isReview == true) (list?.size ?: 0) + 1 else (list?.size ?: 0)
    }

    override fun getItemViewType(position: Int): Int {
        if (position < list?.size ?: 0 - 1) {
            return ITEM_VIEW_TYPE
        }
        return END_ITEM_VIEW_TYPE
    }

    private fun isEndItemView(viewType: Int): Boolean {
        return viewType == END_ITEM_VIEW_TYPE
    }

}

/**
 * 点击继续拍照的点击事件回调
 */
interface OnImageGalleryAddPhotoClickListener1 {
    fun onAddPhotoItemClick()
}

class ImageGalleryViewHolder1(itemView: View) : RecyclerView.ViewHolder(itemView) {

    var itemRootView: ConstraintLayout? = null
    var ivPhoto: ImageView? = null
    var ivAddPhoto: ImageView? = null

    init {
        ivPhoto = itemView.findViewById(R.id.ivPhoto)
        ivAddPhoto = itemView.findViewById(R.id.ivAddPhoto)
        itemRootView = itemView.findViewById(R.id.itemRootView)

        ivPhoto?.setRound(itemView.context.resources.getDimensionPixelSize(R.dimen.hybrid_image_gallery_dialog_round_size)
            .toFloat())
    }
}

class ImageGalleryZoomOutPageTransformer1 : ViewPager2.PageTransformer {

    override fun transformPage(view: View, position: Float) {
        val pageWidth = view.width
        val pageHeight = view.height
        val scaleFactor = MIN_SCALE.coerceAtLeast(1 - abs(position))
        val vertMargin = pageHeight * (1 - scaleFactor) / 2
        val horzMargin = pageWidth * (1 - scaleFactor) / 2
        when {
            position < -1 -> {
                view.translationX = horzMargin - vertMargin / 2
                // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.alpha = MIN_ALPHA
                view.scaleX = MIN_SCALE
                view.scaleY = MIN_SCALE
            }
            position <= 1 -> {
                // [-1,1]
                if (position < 0) {
                    view.translationX = horzMargin - vertMargin / 2
                    view.scaleX = 1 + 0.3f * position
                    view.scaleY = 1 + 0.3f * position
                } else {
                    view.translationX = -horzMargin + vertMargin / 2
                    view.scaleX = 1 - 0.3f * position
                    view.scaleY = 1 - 0.3f * position
                }

                // Scale the page down (between MIN_SCALE and 1)

                // Fade the page relative to its size.
                view.alpha =
                    MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA)
            }
            else -> { // (1,+Infinity]
                view.translationX = -horzMargin + vertMargin / 2
                view.scaleX = MIN_SCALE
                view.scaleY = MIN_SCALE
                view.alpha = MIN_ALPHA
            }
        }
    }

    companion object {
        private const val MIN_SCALE = 0.7f
        private const val MIN_ALPHA = 0.5f
    }
}

interface OnImageDialogDismissListener1 {
    fun onDismiss(resultJson:String)
}
class AXXAlbumCamera(var context: Context): Camera<AXXImageCameraWrapper, VideoCameraWrapper> {

    override fun image(): AXXImageCameraWrapper {
        return AXXImageCameraWrapper(context)
    }

    override fun video(): VideoCameraWrapper {
        return VideoCameraWrapper(context)
    }
}
public class AXXCameraActivity extends BaseActivity {

    public static final String INSTANCE_CAMERA_TYPE = "INSTANCE_CAMERA_TYPE";
    private int cameraType = 1; // 前置、后置 1 后置 2 前置
    private static final int CODE_PERMISSION_IMAGE = 1;

    public static final int CAMERA_TYPE_BACK = 1; // 后
    public static final int CAMERA_TYPE_FRONT = 2; // 前

    private static final int CODE_ACTIVITY_TAKE_IMAGE = 1;

    public static Action<String> sResult;
    public static Action<String> sCancel;

    private String mCameraFilePath;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SystemBar.setStatusBarColor(this, Color.TRANSPARENT);
        SystemBar.setNavigationBarColor(this, Color.TRANSPARENT);
        SystemBar.invasionNavigationBar(this);
        if (savedInstanceState == null) {
            Bundle bundle = getIntent().getExtras();
            assert bundle != null;
            cameraType = bundle.getInt(INSTANCE_CAMERA_TYPE);
            requestPermission(PERMISSION_TAKE_PICTURE , CODE_PERMISSION_IMAGE);
        } else {
            cameraType = savedInstanceState.getInt(INSTANCE_CAMERA_TYPE);
        }
    }

    @Override
    protected void onPermissionGranted(int code) {
        super.onPermissionGranted(code);
        if(code == CODE_PERMISSION_IMAGE) {
            mCameraFilePath = AlbumUtils.randomJPGPath(this);
            ReportLog.INSTANCE.method("AXXCameraActivity"
                    , "onPermissionGranted"
                    , "要拍照的路径:" + mCameraFilePath);
            takeImage(this, CODE_ACTIVITY_TAKE_IMAGE, new File(mCameraFilePath));
        }
    }

    @Override
    protected void onPermissionDenied(int code) {
        super.onPermissionDenied(code);
        if(code == CODE_PERMISSION_IMAGE) {
            ToastUtil.showToast("您还没有拍照和存储的权限,请前往权限中心进行设置");
            callbackCancel();
        }
    }

    /**
     * 拍照
     * @param activity
     * @param requestCode
     * @param outPath
     */
    private void takeImage(@NonNull Activity activity, int requestCode, File outPath) {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        Uri uri = AlbumUtils.getUri(activity, outPath);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        if(cameraType == CAMERA_TYPE_FRONT) {
            intent.putExtra("android.intent.extra.USE_FRONT_CAMERA", true);
        } else {
            intent.putExtra("android.intent.extra.USE_FRONT_CAMERA", false);
        }
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        activity.startActivityForResult(intent, requestCode);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putInt(INSTANCE_CAMERA_TYPE, cameraType);
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case CODE_ACTIVITY_TAKE_IMAGE: {
                if (resultCode == RESULT_OK) {
                    callbackResult();
                } else {
                    callbackCancel();
                }
                break;
            }
            default: {
                throw new AssertionError("This should not be the case.");
            }
        }
    }

    private void callbackResult() {
        if (sResult != null) sResult.onAction(mCameraFilePath);
        sResult = null;
        sCancel = null;
        finish();
    }

    private void callbackCancel() {
        if (sCancel != null) sCancel.onAction("User canceled.");
        sResult = null;
        sCancel = null;
        finish();
    }
}

hybrid_activity_image_gallery.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/imageGalleryRootView"
    android:background="#00000000"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/tvIndex"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/pageGroup"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:text="0/0"
        android:textColor="@color/white"
        android:textStyle="bold"
        android:textSize="16sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintVertical_bias="0.8"/>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/pageGroup"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:clipChildren="false"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintHeight_percent="0.6">

        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/imagePager"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:clipChildren="false"
            android:overScrollMode="never"
            app:layout_constraintHeight_percent="1"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintDimensionRatio="h,548:750"/>

    </androidx.constraintlayout.widget.ConstraintLayout>

    <androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/ivReset"
        app:layout_constraintTop_toBottomOf="@+id/pageGroup"
        app:layout_constraintLeft_toLeftOf="@id/pageGroup"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/ivDeleted"
        app:layout_constraintHorizontal_chainStyle="packed"
        android:src="@mipmap/icon_image_gallery_reset"
        app:layout_constraintDimensionRatio="64:100"
        app:layout_constraintHeight_percent="0.09"
        android:layout_marginRight="17dp"
        android:layout_width="0dp"
        android:layout_height="0dp"/>

    <androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/ivDeleted"
        app:layout_constraintTop_toBottomOf="@+id/pageGroup"
        app:layout_constraintRight_toRightOf="@id/pageGroup"
        app:layout_constraintLeft_toRightOf="@+id/ivReset"
        app:layout_constraintBottom_toBottomOf="parent"
        android:src="@mipmap/icon_image_gallery_deleted"
        android:layout_marginLeft="17dp"
        app:layout_constraintDimensionRatio="64:100"
        app:layout_constraintHeight_percent="0.09"
        android:layout_width="0dp"
        android:layout_height="0dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

hybrid_item_image_gallery.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/itemRootView"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="@drawable/hybrid_bg_photo_grallery">

    <androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/ivPhoto"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scaleType="centerCrop"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

hybrid_item_image_gallery_photograph.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/itemRootView"
    android:background="@drawable/hybrid_bg_add_photo_grallery"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/ivAddPhoto"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintDimensionRatio="100:83"
        app:layout_constraintWidth_percent="0.13"
        android:src="@mipmap/icon_photograph"/>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值