Android仿微信的图片裁剪库 ------ 持续开发中(裁剪框相关)

我们已经实现了图片的缩放以及图片的归位和动画,下面我们可以尝试加入裁剪框

数据层控制裁剪框的移动我参考了网上的开源项目,个人认为方法比较巧妙,但是使用的方法可能乍一看让人有点摸不着头脑,借此机会我也来学习和解析一下。

 

一般来说,裁剪框具有八个可操作的区域:四个角和四个边

 

enum Anchor {
        LEFT(1),
        RIGHT(2),
        TOP(4),
        BOTTOM(8),
        LEFT_TOP(5),
        RIGHT_TOP(6),
        LEFT_BOTTOM(9),
        RIGHT_BOTTOM(10);

        int v;

        static final int[] PN = {1, -1};

        Anchor(int v) {
            this.v = v;
        }

        public void move(RectF win, RectF frame, float dx, float dy) {
            float[] maxFrame = cohesion(win, CLIP_MARGIN);
            float[] minFrame = cohesion(frame, CLIP_FRAME_MIN);
            float[] theFrame = cohesion(frame, 0);

            float[] dxy = {dx, 0, dy};
            for (int i = 0; i < 4; i++) {
                if (((1 << i) & v) != 0) {

                    int pn = PN[i & 1];

                    theFrame[i] = pn * getRealValue(pn * (theFrame[i] + dxy[i & 2]),
                            pn * maxFrame[i], pn * minFrame[i + PN[i & 1]]);
                }
            }

            frame.set(theFrame[0], theFrame[2], theFrame[1], theFrame[3]);
        }

        public static float getRealValue(float v, float min, float max) {
            return Math.min(Math.max(v, min), max);
        }

        public static float[] cohesion(RectF win, float v) {
            return new float[]{
                    win.left + v, win.right - v,
                    win.top + v, win.bottom - v
            };
        }

        public static boolean isCohesionContains(RectF frame, float v, float x, float y) {
            return frame.left + v < x && frame.right - v > x
                    && frame.top + v < y && frame.bottom - v > y;
        }

        public static Anchor valueOf(int v) {
            Anchor[] values = values();
            for (Anchor anchor : values) {
                if (anchor.v == v) {
                    return anchor;
                }
            }
            return null;
        }
    }

我们重点分析一下这个枚举类,我们可以看到主要的方法是move方法,接收四个参数,前两个矩阵分别是最大窗口和当前窗口,通过getFrame方法得到四个边界,分别是最大边界,最小边界和当前边界。

float[] dxy = {dx, 0, dy};
            for (int i = 0; i < 4; i++) {
                if (((1 << i) & v) != 0) {

                    int pn = PN[i & 1];

                    theFrame[i] = pn * revise(pn * (theFrame[i] + dxy[i & 2]),
                            pn * maxFrame[i], pn * minFrame[i + PN[i & 1]]);
                }
            }

            frame.set(theFrame[0], theFrame[2], theFrame[1], theFrame[3]);

在这一堆诡异的位运算之前,我们观察一下枚举类的值有没有什么奥秘

LEFT(1),//1
        RIGHT(2),//10
        TOP(4),//100
        BOTTOM(8),//1000
        LEFT_TOP(5),//101
        RIGHT_TOP(6),//110
        LEFT_BOTTOM(9),//1001
        RIGHT_BOTTOM(10);//1010

这里为什么不用1 2 3 4 5 6 7 8而是1 2 4 8 5 6 9 10呢

我们看一下二进制表示,可以发现left---第0位是1  bottom----第3位是1

那么left_bottom----第0位和第3位是1

这里就是很巧妙的地方,为我们节省了很多的if--else判断。

((1 << i) & v) != 0

这里我们就得到了v(当前锚点的值)的第i位是不是1,从而判断计算新的rectF需要进行哪些计算。

static final int[] PN = {1, -1};
 



int pn = PN[i & 1];

这里我们看到使用i & 1来计算位移的正负

即左和上相关锚点pn为正  右和下相关锚点pn为负

我们以右下角向上移动为例进行分析

首先right_bottom第一位和第三位为1 也就是在i=1和i=3时会进入计算

pn = -1

这里pn的作用其实就是不用再写分支进行判断,因为对于top 大于最大边框是合法值,而对于bottom,小于最大边框是合法值。

这几行代码很精简,可能乍一看可读性不如一堆if else,但是真的能让我们从中学到许多。

现在关于裁剪框RectF的更新已经完成了,接下来就是根据矩阵进行裁剪框的绘制啦!

 

我们明天再见啦~

 

项目github地址:https://github.com/lqy20160609/ImageClip

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值