Android拖放startDragAndDrop拖拽Glide灵活加载堆叠圆角图,Kotlin(6)

Android拖放startDragAndDrop拖拽Glide灵活加载堆叠圆角图,Kotlin(6)

Android拖放startDragAndDrop拖拽Glide加载堆叠圆角图,Kotlin(5)-CSDN博客文章浏览阅读1.3k次。Android DynamicGrid:拖曳交换位置Android DynamicGrid是一个第三方开源项目,DynamicGrid在github上的项目主页是:https://github.com/askerov/DynamicGrid它实现在一个网格布局内,拖曳任意子view实现动态的交换位置,这很类似手机的桌面,手机桌面的图标,均可自由拖曳实现摆放位置的交换,如动图所示:_android 拖拽交换位置。Android View拖拽startDragAndDrop,Kotlin-CSDN博客。https://blog.csdn.net/zhangphil/article/details/134269432上面文章(5)虽然可以做到拖拽实现Glide动态加载1张或若干张堆叠的旋转图片,但需要在xml布局和上层Kotlin代码中小心谨慎的写好(计算好)尺寸,否则会显示布局和View异常,不够灵活。这次,现在改造文章(5)中的实现,实现低代码、灵活加载旋转的堆叠图。

Kotlin 复制代码
import android.content.ClipData
import android.content.Context
import android.graphics.Canvas
import android.graphics.Point
import android.os.Bundle
import android.util.Log
import android.view.DragEvent
import android.view.LayoutInflater
import android.view.View
import android.view.View.OnDragListener
import android.view.View.OnLongClickListener
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.children
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners

class MainActivity : AppCompatActivity() {
    companion object {
        const val TAG = "fly"
        const val DEGREE = -10 //图片旋转的角度。
        const val RADIUS = 30 //图片的圆角半径。
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val shadowBuilder = createDragShadowBuilder()
        setData(shadowBuilder.getShadowView())

        val triggerView = findViewById<ImageView>(R.id.image)
        triggerView.setOnLongClickListener(object : OnLongClickListener {
            //长按事件触发拖拽.
            override fun onLongClick(v: View?): Boolean {
                val data = ClipData.newPlainText("name", "phil") //测试数据。
                triggerView.startDragAndDrop(
                    data,
                    shadowBuilder,
                    null,
                    0 or View.DRAG_FLAG_GLOBAL or View.DRAG_FLAG_OPAQUE
                )

                return true
            }
        })

        triggerView.setOnDragListener(object : OnDragListener {
            override fun onDrag(v: View?, event: DragEvent?): Boolean {
                when (event?.action) {
                    DragEvent.ACTION_DRAG_STARTED -> {
                        //拖放开始
                        Log.d(TAG, "ACTION_DRAG_STARTED")
                    }

                    DragEvent.ACTION_DRAG_ENTERED -> {
                        //进入imageView
                        Log.d(TAG, "ACTION_DRAG_ENTERED")
                    }

                    DragEvent.ACTION_DRAG_ENDED -> {
                        //拖放结束
                        Log.d(TAG, "ACTION_DRAG_ENDED")
                    }

                    DragEvent.ACTION_DRAG_EXITED -> {
                        //离开imageView
                        Log.d(TAG, "ACTION_DRAG_EXITED")
                    }
                }

                return true
            }
        })
    }

    private fun createDragShadowBuilder(): MyDragShadowBuilder {
        val shadowView = LayoutInflater.from(this).inflate(R.layout.dnd, null)
        return MyDragShadowBuilder(this, shadowView)
    }

    private fun setData(viewGroup: View) {
        //从1和4两个数字中随机选一个。
        var cnt = intArrayOf(1, 4).random()
        Log.d(TAG, "cnt=$cnt")

        val number = viewGroup.findViewById<TextView>(R.id.number)
        when (cnt) {
            1 -> {
                //只显示一张。
                number.text = "1"

                val fl: FrameLayout? = viewGroup as? FrameLayout
                fl?.children?.filter {
                    (it as? ImageView)?.tag == resources.getString(R.string.normal_image_view_tag)
                }?.forEach { view ->
                    view.apply {
                        View.GONE
                    }
                }
            }

            4 -> {
                //显示重叠在一起的4张。
                number.text = "4"

                val resIds = arrayOf(
                    R.mipmap.pic1,
                    R.mipmap.pic2,
                    R.mipmap.pic3
                )

                val fl: FrameLayout? = viewGroup as? FrameLayout
                fl?.children?.filter {
                    (it as? ImageView)?.tag == resources.getString(R.string.normal_image_view_tag)
                }?.forEachIndexed { index, view ->
                    view.apply {
                        View.VISIBLE
                    }

                    val degree = (resIds.size - index) * DEGREE
                    Log.d(TAG, "index=$index degree=$degree")

                    view.rotation = degree.toFloat()

                    GlideApp.with(this)
                        .load(resIds[index])
                        .transform(CenterCrop(), RoundedCorners(RADIUS)) //先中心缩放,再切圆角。
                        .override(
                            resources.getDimensionPixelSize(R.dimen.image_size_w),
                            resources.getDimensionPixelSize(R.dimen.image_size_h)
                        ).placeholder(R.drawable.ic_launcher_foreground)
                        .error(android.R.drawable.stat_notify_error)
                        .into(view as ImageView)
                }
            }
        }

        val folder = viewGroup.findViewById<ImageView>(R.id.folder)
        //封面
        GlideApp.with(this)
            .load(R.mipmap.pic4)
            .transform(CenterCrop(), RoundedCorners(RADIUS)) //先中心缩放,再切圆角。
            .override(
                resources.getDimensionPixelSize(R.dimen.image_size_w),
                resources.getDimensionPixelSize(R.dimen.image_size_h)
            ).placeholder(R.drawable.ic_launcher_foreground)
            .error(android.R.drawable.stat_notify_error)
            .into(folder)
    }

    class MyDragShadowBuilder(ctx: Context, private var mShadow: View) :
        View.DragShadowBuilder() {
        //放大参数 1.5 , 2.0
        //适当的放大拖拽区域的面积,否则因为图片旋转,左右两侧和顶部因为旋转半径,图会被切边。
        //简单的说,绘制略微大一些的区域,容纳图片旋转,半径扫过的区域。
        private val width: Int =
            (ctx.resources.getDimensionPixelSize(R.dimen.image_size_w) * 1.5).toInt()
        private val height: Int =
            (ctx.resources.getDimensionPixelSize(R.dimen.image_size_h) * 2.0).toInt()

        fun getShadowView(): View {
            return mShadow
        }

        override fun onProvideShadowMetrics(outShadowSize: Point?, outShadowTouchPoint: Point?) {
            //拖动图像的宽和高
            outShadowSize?.set(width, height)

            //手指在拖动图像的位置 中点
            outShadowTouchPoint?.set(width / 2, height / 2)
        }

        override fun onDrawShadow(canvas: Canvas) {
            mShadow.measure(width, height)
            mShadow.layout(0, 0, width, height)
            mShadow.draw(canvas)

            Log.d(TAG, "onDrawShadow width=${mShadow.width} height=${mShadow.height}")
        }
    }
}

dnd.xml:

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@android:color/holo_orange_light">

    <ImageView
        android:id="@+id/iv1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:tag="@string/normal_image_view_tag" />

    <ImageView
        android:id="@+id/iv2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:tag="@string/normal_image_view_tag" />

    <ImageView
        android:id="@+id/iv3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:tag="@string/normal_image_view_tag" />

    <ImageView
        android:id="@+id/folder"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />


    <androidx.cardview.widget.CardView
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_gravity="top|right"
        app:cardBackgroundColor="@android:color/holo_red_light"
        app:cardCornerRadius="15dp">

        <TextView
            android:id="@+id/number"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="--"
            android:textColor="@android:color/white"
            android:textSize="15dp" />
    </androidx.cardview.widget.CardView>
</FrameLayout>

注意,根布局layout如果不使用FrameLayout,而是其他layout布局如RelativeLayout或ConstraintLayout,xml里面定义的居中放置子View失效。

dimens.xml:

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="image_size_w">180dp</dimen>
    <dimen name="image_size_h">120dp</dimen>
</resources>

strings.xml:

XML 复制代码
<resources>
    <string name="normal_image_view_tag">normal_image_view_tag</string>
</resources>

拖拽1张图片:

拖拽4张图片,背景3张旋转,封面不旋转:

Android改造CardView为圆形View,Kotlin_android 圆形view-CSDN博客文章浏览阅读1k次。可以利用androidx.cardview.widget.CardView的cardCornerRadius特性,将CardView改造成一个圆形的View,技术实现的关键首先设定CardView为一个宽高相等的View(正方形),然后将radius特意设置成宽度(或高度,一样,因为正方形,宽高相等)的1/2,此时CardView自然就变成一个圆。Android RoundedBitmapDrawable:Android官方的圆角图形图象实现方案_android 官方圆角-CSDN博客。_android 圆形viewhttps://blog.csdn.net/zhangphil/article/details/133346170

相关推荐
DogDaoDao3 小时前
Android 硬件编码器参数完全指南:MediaCodec 深度解析
android·音视频·视频编解码·h264·硬编码·视频直播·mediacodec
JohnnyDeng944 小时前
Android 自定义 View:Canvas 绘图与事件分发深度解析
android
Android小码家7 小时前
Framework之Launcher小窗开发
android·framework·虚拟屏·小窗
赏金术士7 小时前
第七章:状态管理实战与架构总结
android·ui·kotlin·compose
颂love8 小时前
MySQL的执行流程
android·数据库·mysql
云起SAAS13 小时前
抖音小游戏源码 - 消消乐 | 含激励广告+成就系统 | 开箱即用商业级消除游戏模板
android·游戏·广告联盟·看激励广告联盟流量主·抖音小游戏源码 - 消消乐
大貔貅喝啤酒14 小时前
基于Windows下载安装Android Studio 3.3.2版本教程(2026详细图文版)
android·java·windows·android studio
程序员码歌14 小时前
OpenSpec 到 Superpowers:AI 编码从说清到做对
android·前端·人工智能
2501_9151063214 小时前
深入解析无源码iOS加固原理与方案,保护应用安全
android·安全·ios·小程序·uni-app·cocoa·iphone
黄林晴18 小时前
重磅官宣:Android UI 开发正式进入 Compose-first 时代
android·google io