模仿微信图片编辑器--动画实现向上弹出文字编辑框(遮罩)界面

豪言壮志

今天天气不错,挺风和日丽的,出去逛逛街,溜溜弯,拍上一张美图,配上高逼格的格言警句,发到朋友圈,一片鸡汤文就此诞生。。。

最近会有事没事会在朋友圈发动态:写一句格言警句,配上一张意境美图。因为懒,我总是在想,图片能够自动随机网上选择该多好,能不能直接将文字写在图片上,能不能一键分享到朋友圈,再配上二维码,那感觉,妙。。。

花半天时间找了一下,目标就它了:微信的「图片编辑器」,然后自己配上图片的素材,不就能满足上述条件嘛。

可是图片素材只能是手机相册,万一以后用完了怎么办,而且没有二维码。微信估计不干了:你行你上啊。对啊,那就自己干。

确定效果图

先不说马赛克、涂鸦、裁剪等功能,我现在需要的是文字编辑的功能,所以就先搞一搞这个。

微信的效果我就不贴出来了,大家估计都体验过吧,哈哈。

什么,你没有用过?呵呵,(尴尬),那就只是你一个而已。。。对,你应该与时俱进一下。

纳尼,你们都没有用过?!好吧,你们怎么看到我的文章的,难道不是搜索微信图片编辑器过来的吗~

给大家贴上目标效果图:

editMask

哦哦,你要微信的效果是吧,OK,拿出你的手机,给我发张图片就可以啦。

开始实现布局界面

好,开始撸代码了。

创建工程,引用最新的 Kotlin 库:

// dependency.gradle
def anko_version = "0.10.5"

ext {
    ankoSdk = "org.jetbrains.anko:anko-sdk25:$anko_version" // sdk15, sdk19, sdk21, sdk23 are also available
    ankoAppCompat = "org.jetbrains.anko:anko-appcompat-v7:$anko_version"
    ankoListeners = "org.jetbrains.anko:anko-sdk25-listeners:$anko_version"
}

// basemodule.gradle
dependencies {
     // 最新的 api 引用方式
    api ankoSdk
    api ankoAppCompat
    api ankoListeners
}
在 `MainActivity` 中创建布局:
relativeLayout {
    editToolBar = linearLayout {
        button("编辑")
    }

    // todo: 之后采用 constraintLayout
    editMask = verticalLayout {
        relativeLayout {
            textView("取消").lparams(wrapContent, wrapContent) {
                alignParentLeft()
            }

            textView("完成").lparams {
                alignParentRight()
            }
        }

        editView = editText {
            padding = 15
            gravity = Gravity.TOP
            backgroundColor = Color.GREEN
            // 刚进入界面时不获取焦点
            isFocusable = false
        }.lparams(matchParent, 0, 1f)

        // scrollView 是为 view 漂浮在软键盘上做准备
        scrollView {
            linearLayout {
                textView("tool bar")
            }
        }
    }.lparams(matchParent, matchParent) {
        alignParentBottom()
    }
}
额,界面效果丑是丑了点,但咱看中的是实力,对吧。况且,以后咱可以美颜呀~~

向上弹出界面

网上通用的几个解决方案:Dialog,PopupWindow,Activity 等都可以实现相同的效果。

但是我觉得比较重,再加上要写比较多的代码(这是主要原因),所以我采用动画的方式实现这个效果。

给「编辑」按钮添加点击事件,开启动画:

onClick {
    ValueAnimator
            .ofInt(0, rootView.height) // 设置遮罩的高度变化是从 0 到 整个界面的高度
            .setDuration(100) // 动画时长:100ms
            .apply {
                // 添加监听,动画中数值的每一次变化,都是遮罩界面高度的变化
                addUpdateListener {
                    editMask.layoutParams = editMask.layoutParams.apply {
                        // 遮罩高度动态变化,值为每次动画改变后的值
                        height = it.animatedValue as Int
                    }
                }
            }
            .start() // 开始动画
}
好啦,基本上完事大吉啦,聪明如你,肯定知道这个动画什么意思吧。如果你第一次接触,就仔细看代码,有注释哦。

细节优化

动画启动时,需要隐藏「编辑」按钮;

点击「取消」或「完成」时,隐藏「编辑界面」,显示「编辑」按钮;

动画不需要每次都创建等等。

最终界面布局:

relativeLayout {
    editToolBar = linearLayout {
        button("编辑").onClick { 
            openEditMask()
        }
    }.lparams(matchParent, wrapContent) {
        alignParentBottom()
    }

    // todo: 之后采用 constraintLayout
    editMask = verticalLayout {
        relativeLayout {
            textView("取消").lparams(wrapContent, wrapContent) {
                alignParentLeft()
            }.onClick { closeEditMask() }

            textView("完成").lparams {
                alignParentRight()
            }.onClick { closeEditMask() }
        }

        editView = editText {
            padding = 15
            gravity = Gravity.TOP
            backgroundColor = Color.GREEN
            // 刚进入界面时不获取焦点
            isFocusable = false
        }.lparams(matchParent, 0, 1f)

        // scrollView 是为 view 漂浮在软键盘上做准备
        scrollView {
            linearLayout {
                textView("tool bar")
            }
        }

    }.lparams(matchParent, 0) {
        alignParentBottom()
    }
}
提取出来的方法:
// 关闭遮罩
private fun openEditMask() {
    openAnimator.start()
    editToolBar.visibility = View.GONE
}

// 关闭遮罩
private fun closeEditMask() {
    closeAnimator.apply {
        addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator?) {
                editToolBar.visibility = View.VISIBLE
            }
        })
    }.start()
}

// 呈现动画
private val openAnimator by lazy {
    ValueAnimator
            .ofInt(0, window.decorView.height)
            .setDuration(100)
            .apply {
                addUpdateListener {
                    val h = it.animatedValue as Int
                    editMask.layoutParams = editMask.layoutParams.apply {
                        height = h
                    }
                }
            }
}

// 关闭动画
private val closeAnimator by lazy {
    ValueAnimator
            .ofInt(window.decorView.height, 0)
            .setDuration(100)
            .apply {
                addUpdateListener {
                    val h = it.animatedValue as Int
                    editMask.layoutParams = editMask.layoutParams.apply {
                        height = h
                    }
                }
            }
}

结束

这个小功能算是搞完了,感觉好简单啊,真不知道为什么我弄了一天才写出来,哎,看来我不是天才,你才是啊。

如果文章对你有帮助的话,欢迎关注公众号:goodKotlin,你的关注,就是最大的支持。

文章源码:GitHub: Ethoshttps://github.com/xwdoor/Ethos),欢迎大家给颗星星,哈哈。

推荐阅读:
1. 图片编辑器–向上弹出文字编辑框(遮罩)界面
2. 图片编辑器–视图布局 View 悬浮在软键盘上

微信公众号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值