圖片操作系列 —(2)手勢(shì)旋轉(zhuǎn)圖片

前言

在上次的文章:圖片操作系列 —(1)手勢(shì)縮放圖片功能中,我們已經(jīng)學(xué)會(huì)了如何用手勢(shì)來對(duì)圖片進(jìn)行縮放乙墙。這次我們繼續(xù)來看第二個(gè)操作宁舰,那就是如何用手勢(shì)來旋轉(zhuǎn)圖片。

所以我們本文我們一共要實(shí)現(xiàn)二個(gè)功能:

  1. 根據(jù)二個(gè)手指頭的旋轉(zhuǎn)來使圖片跟著旋轉(zhuǎn)
  2. 當(dāng)二個(gè)手指頭放開后额衙,圖片會(huì)自動(dòng)回歸到合適的位置。

我說明下第二個(gè)功能點(diǎn)的意思:什么叫回歸到合適的位置怕吴,比如如圖一窍侧,我們只轉(zhuǎn)動(dòng)了一點(diǎn)點(diǎn),沒有超過45度转绷,然后放在手指伟件,然后就會(huì)回到圖二的樣子。但是如果超過了45度议经,然后放開手指斧账,就回變成圖三的樣子。

圖一

圖二

圖三

前面基本的東西說明我都不說了煞肾。比如Matrix等知識(shí)咧织。大家可以直接參考圖片操作系列 —(1)手勢(shì)縮放圖片功能

ps:我這邊可以再貼出相關(guān)基礎(chǔ)的鏈接:
android matrix 最全方法詳解與進(jìn)階(完整篇)
Android Matrix


根據(jù)二個(gè)手指頭的旋轉(zhuǎn)來使圖片跟著旋轉(zhuǎn):

我們知道使圖片進(jìn)行旋轉(zhuǎn)特定的角度很簡(jiǎn)單:

使用Matrix.postRotate(float degrees, float px, float py)方法即可籍救。繞著(px,py)點(diǎn)進(jìn)行旋轉(zhuǎn)degrees角度习绢。

所以我們的問題就變成了如果獲取二個(gè)手指頭在做旋轉(zhuǎn)手勢(shì)的時(shí)候,相應(yīng)的角度的變化蝙昙,從而通過Matrix.postRotate方法來讓圖片也跟著變化闪萄。

1.獲取二個(gè)手指頭的手勢(shì)監(jiān)聽

圖片操作系列 —(1)手勢(shì)縮放圖片功能文中我們知道,控制圖片的縮放是專門有個(gè)ScaleGestureDetector;在OnTouch事件中把相應(yīng)的事件傳遞給ScaleGestureDetector奇颠。然后監(jiān)聽處理败去。我們也可以模仿著寫一個(gè)RotateGestureDetector來進(jìn)行圖片旋轉(zhuǎn)的監(jiān)聽和處理。

public interface IRotateDetector {

    /**
     * handle rotation in onTouchEvent
     *
     * @param event The motion event.
     * @return True if the event was handled, false otherwise.
     */
    boolean onTouchEvent(MotionEvent event);
    
        /**
     * is the Gesture Rotate
     *
     * @return true:rotating;false,otherwise
     */
    boolean isRotating();
}

public class RotateGestureDetector implements IRotateDetector{
    
    private int mLastAngle = 0;//最后一次的角度值
    private IRotateListener mListener;//用來旋轉(zhuǎn)的回調(diào)Listener
    private boolean mIsRotate;//是否處于旋轉(zhuǎn)
    
    //用來設(shè)置回調(diào)Listener的方法
    public void setRotateListener(IRotateListener listener) {
        this.mListener = listener;
    }
    
    //用來接收觸摸事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return doRotate(event);
    }
    
    //真正的計(jì)算手勢(shì)操作所得到的角度值的方法大刊,及回調(diào)調(diào)用为迈。
    private boolean doRotate(MotionEvent ev) {
        if (ev.getPointerCount() != 2) {
            return false;
        }
        //Calculate the angle between the two fingers
        int pivotX = (int) (ev.getX(0) + ev.getX(1)) / 2;
        int pivotY = (int) (ev.getY(0) + ev.getY(1)) / 2;
        float deltaX = ev.getX(0) - ev.getX(1);
        float deltaY = ev.getY(0) - ev.getY(1);

        double radians = Math.atan(deltaY / deltaX);
      
        int degrees = (int) Math.round(Math.toDegrees(Math.atan2(deltaY,deltaX)));
       
        switch (ev.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                mLastAngle = degrees;
                mIsRotate = false;
                break;
            case MotionEvent.ACTION_UP:
                mIsRotate = false;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                mLastAngle = degrees;
                mIsRotate = false;
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_POINTER_UP:
                mIsRotate = false;
                upRotate(pivotX, pivotY);
                mLastAngle = degrees;
                break;
            case MotionEvent.ACTION_MOVE:
                mIsRotate = true;
                int degreesValue = degrees  - mLastAngle;
                if (degreesValue > 45) {
                    //Going CCW across the boundary
                    rotate(-5, pivotX, pivotY);
                } else if (degreesValue < -45) {
                    //Going CW across the boundary
                    rotate(5, pivotX, pivotY);
                } else {
                    //Normal rotation, rotate the difference
                    rotate(degreesValue, pivotX, pivotY);
                }
                //Save the current angle
                mLastAngle = degrees;
                break;
        }
        return true;
    }
    
    //回調(diào)的方法之一:控制圖片根據(jù)手勢(shì)的變化實(shí)時(shí)進(jìn)行旋轉(zhuǎn)
    private void rotate(int degree, int pivotX, int pivotY) {
        if (mListener != null) {
            mListener.rotate(degree, pivotX, pivotY);
        }
    }

    //回調(diào)的方法之一:最后某個(gè)手指放開后,控制圖片自動(dòng)回歸到合適的位置缺菌。
    private void upRotate(int pivotX, int pivotY) {
        if (mListener != null) {
            mListener.upRotate(pivotX, pivotY);
        }
    }

}

2.獲取二個(gè)手指頭的角度變化

所以我們只需要來分析一下具體OnTouch事件中的doRotate方法即可:

//真正的計(jì)算手勢(shì)操作所得到的角度值的方法,及回調(diào)調(diào)用搜锰。
private boolean doRotate(MotionEvent ev) {
    //如果觸摸的手指頭不是2個(gè)伴郁,直接返回。
    if (ev.getPointerCount() != 2) {
        return false;
    }
    
    //獲取二個(gè)手指頭的中心點(diǎn)的X與Y值蛋叼,等會(huì)選擇二個(gè)手指頭的中心點(diǎn)作為旋轉(zhuǎn)的中心
    int pivotX = (int) (ev.getX(0) + ev.getX(1)) / 2;
    int pivotY = (int) (ev.getY(0) + ev.getY(1)) / 2;
    //獲取二個(gè)手指頭之間的X和Y的差值
    float deltaX = ev.getX(0) - ev.getX(1);
    float deltaY = ev.getY(0) - ev.getY(1);
    //獲取角度
    int degrees = (int) Math.round(Math.toDegrees(Math.atan2(deltaY,deltaX)));
   
    switch (ev.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            mLastAngle = degrees;
            mIsRotate = false;
            break;
        case MotionEvent.ACTION_UP:
            mIsRotate = false;
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            mLastAngle = degrees;
            mIsRotate = false;
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_POINTER_UP:
            mIsRotate = false;
            upRotate(pivotX, pivotY);
            mLastAngle = degrees;
            break;
        case MotionEvent.ACTION_MOVE:
            mIsRotate = true;
            /*
            每次把上一次的角度賦值給mLastAngle焊傅,然后獲取當(dāng)前新獲取的角度degrees,
            二者相減獲取到二個(gè)手指頭在移動(dòng)的時(shí)候相應(yīng)的角度變化鸭栖。
            */
            int degreesValue = degrees  - mLastAngle;
            
            /*
            這里主要出現(xiàn)這么個(gè)情況握巢,二個(gè)手指頭如果相隔有一段距離晕鹊,那么在移動(dòng)的過程中,角度不會(huì)一下子變化很大.
            但是比如我們這里故意二個(gè)手指頭是碰在一起的,然后二個(gè)手指頭稍微動(dòng)一下溅话,你就會(huì)發(fā)現(xiàn)角度變化會(huì)很大歌焦。
            這樣圖片就會(huì)瞬間也旋轉(zhuǎn)了很大的角度飞几,讓人體驗(yàn)感覺很怪,所以我們這里瞬間順時(shí)針或者逆時(shí)針超過45度独撇,都只移動(dòng)5度值。
            */
            if (degreesValue > 45) {
                rotate(-5, pivotX, pivotY);
            } else if (degreesValue < -45) {
                rotate(5, pivotX, pivotY);
            } else {
                rotate(degreesValue, pivotX, pivotY);
            }
            //Save the current angle
            mLastAngle = degrees;
            break;
    }
    return true;
}

doRotate方法中最主要的就是根據(jù)二個(gè)手指頭觸摸獲取到的X,Y的差值绪钥,根據(jù)Math.atan2來獲取到角度关炼。我們具體來看下為什么這樣可以來獲取角度:

先附上一個(gè)基礎(chǔ)概念:Math.atan與Math.atan2

image

假設(shè)我們先點(diǎn)擊了(50,50),再點(diǎn)擊(10,10),這時(shí)候我們的deltaX = 40寸潦,deltaY = 40;也就是說
我們的弧度就是Math.atan2(40,40)见转,而角度就是再用Math.toDegrees對(duì)弧度進(jìn)行轉(zhuǎn)換即可。最終獲得額角度是45度乘客。

我們可以通過圖形來查看為什么Math.atan2(40,40)對(duì)應(yīng)的角度是45度淀歇。


image

如果我們的第二個(gè)手指頭從(10,10)移動(dòng)到了(50,10)浪默,也就是說最后變成了Math.atan2(40,0),根據(jù)圖形來看我們就知道是:

image

所以一共旋轉(zhuǎn)了45度缀匕,所以我們的圖片也跟著順時(shí)針旋轉(zhuǎn)45度即可乡小。

那假如我們的二個(gè)手指頭的放入順序反過來饵史,變成:

image

那這時(shí)候就變成了Math.atan2(-40,-40),我們根據(jù)圖形就知道了角度:

image

這時(shí)候還是跟剛才一樣的操作满钟,把(10,10)這個(gè)點(diǎn)移動(dòng)到了(50,10)零远,那這時(shí)候就是Math.atan2(-40,0);

image

所以最終得到的旋轉(zhuǎn)的角度是(-135)-(-90) = 45度厌蔽,所以最終也是順時(shí)針旋轉(zhuǎn)45度奴饮。所以我們不管是哪個(gè)手指頭先放下都不影響結(jié)果。

也許有人就會(huì)問了,你這邊按照二個(gè)手指的中點(diǎn)作為旋轉(zhuǎn)中心去旋轉(zhuǎn)逾条,豈不是會(huì)旋轉(zhuǎn)超出原來的圖片的邊界投剥。如果你還記得我們上一篇文章:圖片操作系列 —(1)手勢(shì)縮放圖片功能江锨,這篇文章最后的內(nèi)容講的就是當(dāng)圖片超過邊界,如果能隨著手勢(shì)慢慢回到邊界里面:checkMatrixBounds()酌心。

3.在Activity中設(shè)置Listener來進(jìn)行圖片的旋轉(zhuǎn)

然后我們只需要在相應(yīng)的Activity處對(duì)回調(diào)回來的(degreesValue, pivotX, pivotY)三個(gè)值做相應(yīng)的旋轉(zhuǎn)即可挑豌。

rotateGestureDetector.setRotateListener(new IRotateListener() {
    @Override
    public void rotate(int degree, int pivotX, int pivotY) {
        //圖片跟著手勢(shì)進(jìn)行旋轉(zhuǎn)
        mSuppMatrix.postRotate(degree, pivotX, pivotY);
        //Post the rotation to the image
        checkAndDisplayMatrix();
    }

    @Override
    public void upRotate(int pivotX, int pivotY) {
        
        //當(dāng)手指頭松開的時(shí)候侯勉,讓圖片自動(dòng)更新到合適的位置债蓝。
        float[] v = new float[9];
        mSuppMatrix.getValues(v);
        // calculate the degree of rotation
        int angle = (int) Math.round(Math.toDegrees(Math.atan2(v[Matrix.MSKEW_Y], v[Matrix.MSCALE_X])));

        mRightAngleRunnable = new RightAngleRunnable(angle, pivotX, pivotY);
        photoView.post(mRightAngleRunnable);
    }
});

手指頭松開手圖片自動(dòng)旋轉(zhuǎn)到合適位置:

我們知道饰迹,前面圖片跟著旋轉(zhuǎn),是獲取到了(int degree, int pivotX, int pivotY)這三個(gè)值锹淌,然后讓mSuppMatrix.postRotate(degree, pivotX, pivotY);那我們就當(dāng)手指頭松開的時(shí)候赂摆,獲取到最終這個(gè)圖片比原來變化了多少角度即可钟些。然后根據(jù)這個(gè)當(dāng)前最終圖片的變化角度來進(jìn)行適當(dāng)?shù)男D(zhuǎn),讓其旋轉(zhuǎn)到合適位置汪拥。

我們來具體看怎么實(shí)現(xiàn)的:

@Override
public void upRotate(int pivotX, int pivotY) {
    
    //當(dāng)手指頭松開的時(shí)候篙耗,讓圖片自動(dòng)更新到合適的位置宗弯。
    float[] v = new float[9];
    mSuppMatrix.getValues(v);
    // calculate the degree of rotation
    int angle = (int) Math.round(Math.toDegrees(Math.atan2(v[Matrix.MSKEW_Y], v[Matrix.MSCALE_X])));

    mRightAngleRunnable = new RightAngleRunnable(angle, pivotX, pivotY);
    photoView.post(mRightAngleRunnable);
}

Matrix,中文里叫矩陣辕棚,高等數(shù)學(xué)里有介紹邑狸,在圖像處理方面单雾,主要是用于平面的縮放屿储、平移、旋轉(zhuǎn)等操作茄菊。在Android里面竖哩,Matrix由9個(gè)float值構(gòu)成相叁,是一個(gè)3*3的矩陣。最好記住虑润。如下圖:


image

image
image

我們發(fā)現(xiàn)mSuppMatrix.getValues(v)方法返回的9個(gè)float值中,第一個(gè)為cosX,第四個(gè)為sinX,所以我們就取下標(biāo)為0和3的值渗柿,也就是MSCALE_X和MSKEW_Y。我們用Math.atan2(v[Matrix.MSKEW_Y], v[Matrix.MSCALE_X])來獲取弧度终惑。再用Math.toDegrees來獲取相應(yīng)的最終圖片的旋轉(zhuǎn)的度數(shù)。

public class Matrix {

    public static final int MSCALE_X = 0;   //!< use with getValues/setValues
    public static final int MSKEW_X  = 1;   //!< use with getValues/setValues
    public static final int MTRANS_X = 2;   //!< use with getValues/setValues
    public static final int MSKEW_Y  = 3;   //!< use with getValues/setValues
    public static final int MSCALE_Y = 4;   //!< use with getValues/setValues
    public static final int MTRANS_Y = 5;   //!< use with getValues/setValues
    public static final int MPERSP_0 = 6;   //!< use with getValues/setValues
    public static final int MPERSP_1 = 7;   //!< use with getValues/setValues
    public static final int MPERSP_2 = 8;   //!< use with getValues/setValues
    
    ......
    ......
    ......
}
    

然后我們?cè)侔勋@取到的角度和中心點(diǎn),通過一個(gè)Runnable來進(jìn)行圖片最后的矯正:

mRightAngleRunnable = new RightAngleRunnable(angle, pivotX, pivotY);
photoView.post(mRightAngleRunnable);

我們知道最后是RightAngleRunnable來進(jìn)行圖片的矯正质帅,所以我們具體來分析下這個(gè)Runnable:

class RightAngleRunnable implements Runnable {
        private static final int RECOVER_SPEED = 4;
        private int mOldDegree;
        private int mNeedToRotate;
        private int mRoPivotX;
        private int mRoPivotY;

        RightAngleRunnable(int degree, int pivotX, int pivotY) {
            Log.v("dyp4", "oldDegree:" + degree + "," + "calDegree:" + calDegree(degree));
            this.mOldDegree = degree;
            this.mNeedToRotate = calDegree(degree);
            this.mRoPivotX = pivotX;
            this.mRoPivotY = pivotY;
        }

        //最終計(jì)算需要矯正的角度值
        /*
            例如:
            
            比如最終是60度嫉嘀,這時(shí)候其實(shí)是超過了45度汤善,應(yīng)該矯正成90度,
            所以最終要多給它30度在旱。順時(shí)針多選擇30度。這里計(jì)算會(huì)得到30噪服。
            
            比如如果是-60度,這時(shí)候應(yīng)該是變成-90讀雹顺,所以我們逆時(shí)針多旋轉(zhuǎn)30度。
            這時(shí)候計(jì)算會(huì)得到-30没酣。
            
            如果是20度四康,這時(shí)候沒有超過45度,所以應(yīng)該矯正成0度哎垦,
            所以最終要逆時(shí)針轉(zhuǎn)回20度,所以這里計(jì)算會(huì)得到-20鸳碧。
            
            如果是-120度瞻离,這時(shí)候要變成-90度,所以要順時(shí)針轉(zhuǎn)回30度肉迫,
            所以計(jì)算會(huì)得到30抛猖。
        */
        private int calDegree(int oldDegree) {
            int N = Math.abs(oldDegree) / 45;
            if ((0 <= N && N < 1) || 2 <= N && N < 3) {
                return -oldDegree % 45;
            } else {
                if (oldDegree < 0) {
                    return -(45 + oldDegree % 45);
                } else {
                    return (45 - oldDegree % 45);
                }
            }
        }
        
        
        /*
        我們上面的calDegree方法可以獲得我們需要矯正的角度财著,但是我們不是一下子就讓圖片選擇N度,而是慢慢的轉(zhuǎn)過來伟姐。
        比如我們用RECOVER_SPEED = 4,4度的慢慢來旋轉(zhuǎn)過來懦鼠,不會(huì)給用戶很突兀的感覺肛冶。
        */
        @Override
        public void run() {
            if (mNeedToRotate == 0) {
                return;
            }
            if (photoView == null) {
                return;
            }
            if (mNeedToRotate > 0) {
                //Clockwise rotation
                if (mNeedToRotate >= RECOVER_SPEED) {
                    mSuppMatrix.postRotate(RECOVER_SPEED, mRoPivotX, mRoPivotY);
                    mNeedToRotate -= RECOVER_SPEED;
                } else {
                    mSuppMatrix.postRotate(mNeedToRotate, mRoPivotX, mRoPivotY);
                    mNeedToRotate = 0;
                }
            } else if (mNeedToRotate < 0) {
                //Counterclockwise rotation
                if (mNeedToRotate <= -RECOVER_SPEED) {
                    mSuppMatrix.postRotate(-RECOVER_SPEED, mRoPivotX, mRoPivotY);
                    mNeedToRotate += RECOVER_SPEED;
                } else {
                    mSuppMatrix.postRotate(mNeedToRotate, mRoPivotX, mRoPivotY);
                    mNeedToRotate = 0;
                }
            }


            checkAndDisplayMatrix();
            Compat.postOnAnimation(photoView, this);
        }
    }

結(jié)尾

還是老樣子,希望大家不要吐槽伦乔。有問題留言哈哈。。O(∩_∩)O哈哈~
PS:有好的畫圖軟件介紹嗎。高帖。求介紹o(╥﹏╥)o

附上Demo地址:ScaleImageVewDemo(已經(jīng)把圖片旋轉(zhuǎn)的Activity demo 加入里面)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子吏祸,更是在濱河造成了極大的恐慌,老刑警劉巖鸣驱,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異递胧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)祝闻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贺拣,你說我怎么就攤上這事闪幽。” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵帚湘,是天一觀的道長。 經(jīng)常有香客問我底挫,道長睁枕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮捐晶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘英支。我一直安慰自己,他們只是感情好把敢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布桑阶。 她就那樣靜靜地躺著,像睡著了一般眷篇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上昧港,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天值朋,我揣著相機(jī)與錄音,去河邊找鬼贯底。 笑死,一個(gè)胖子當(dāng)著我的面吹牛得湘,可吹牛的內(nèi)容都是我干的淘正。 我是一名探鬼主播鸿吆,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼乓搬,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了江掩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎任洞,沒想到半個(gè)月后交掏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡见秽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年禀苦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了振乏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宦赠,到底是詐尸還是另有隱情,我是刑警寧澤妙色,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站煌珊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蔬浙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一蜜唾、第九天 我趴在偏房一處隱蔽的房頂上張望袁余。 院中可真熱鬧煤裙,春花似錦硼砰、人聲如沸恶阴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽够滑。三九已至籍茧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吮龄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衙熔,地道東北人红氯。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓茉贡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親悔据。 傳聞我的和親對(duì)象是個(gè)殘疾皇子科汗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 效果圖: Github鏈接:https://github.com/boycy815/PinchImageView ...
    CQ_TYL閱讀 2,216評(píng)論 0 0
  • 概述 項(xiàng)目開發(fā)中兴猩,大家APP開發(fā)一般都會(huì)用到上傳圖片,比如是上傳了自己的生活照箭跳,然后在某個(gè)界面處查看上傳的圖片,這...
    青蛙要fly閱讀 6,200評(píng)論 2 20
  • 手勢(shì)圖片控件 PinchImageView 點(diǎn)擊圖片框架 photoView packagecom.example...
    Ztufu閱讀 723評(píng)論 0 1
  • 源碼地址 實(shí)現(xiàn)原理概覽 我們要實(shí)現(xiàn)手指控制圖片的平移获询、旋轉(zhuǎn)吉嚣、縮放梢薪,首先得知道手指做了什么動(dòng)作尝哆,比如用戶兩指間距離是...
    籬開羅閱讀 5,856評(píng)論 15 12
  • 沒有選擇權(quán),就意味著沒有自由琐馆。如果父母什么都替孩子拿主意、做選擇谁撼,孩子就不能根據(jù)自己的內(nèi)心和感覺去做事滋饲。孩...
    佛山大樹閱讀 230評(píng)論 0 0