SVG <path> 轉(zhuǎn) Android Canvas Path

SVG <path>中定義了若干指令【詳見(jiàn)MDN
M x,y 移動(dòng)指令,映射Path中的 moveTo
L x,y 畫直線指令越驻,映射Path中的lineTo
H x 畫水平線指令,映射Path中的lineTo,不過(guò)要使用上一個(gè)坐標(biāo)的y
V y 畫垂直線指令道偷,映射Path中的lineTo,不過(guò)要使用上一個(gè)坐標(biāo)的x

C x1,y1,x2,y2,x,y 三次貝塞爾曲線指令缀旁, 映射Path中的cubicTo
S x2,y2,x,y 跟在C指令后面使用,用C指令的結(jié)束點(diǎn)做控制點(diǎn)勺鸦,映射cubicTo
Q x1,y1,x,y 二次貝塞爾曲線指令并巍,映射quadTo
T x,y 跟在Q指令后面使用,使用Q的x,y做控制點(diǎn)祝旷,映射quadTo
Z path關(guān)閉指令履澳,映射close

  • A 指令,用來(lái)畫弧怀跛,還沒(méi)有搞明白怎么處理
  • 在SVG中指令大寫為絕對(duì)坐標(biāo)距贷,小寫為相對(duì)坐標(biāo),但在android Path中似乎是沒(méi)有分別的

分享一個(gè)工具類SvgPathToAndroidPath

/**
 * Created by Shuxin on 2016/8/3.
 */
public class SvgPathToAndroidPath {
    private int svgPathLenght = 0;
    private String svgPath = null;
    private int mIndex;
    private List<Integer> cmdPositions = new ArrayList<>();
    /**
     * M x,y
     * L x,y
     * H x
     * V y
     * C x1,y1,x2,y2,x,y
     * Q x1,y1,x,y
     * S x2,y2,x,y
     * T x,y
     * */
    public Path parser(String svgPath) {
        this.svgPath = svgPath;
        svgPathLenght = svgPath.length();
        mIndex = 0;
        Path lPath = new Path();
        lPath.setFillType(Path.FillType.WINDING);
        //記錄最后一個(gè)操作點(diǎn)
        PointF lastPoint = new PointF();
        findCommand();
        for (int i = 0; i < cmdPositions.size(); i++) {
            Integer index = cmdPositions.get(i);
            switch (svgPath.charAt(index)) {
                case 'm':
                case 'M': {
                    String ps[] = findPoints(i);
                    lastPoint.set(Float.parseFloat(ps[0]), Float.parseFloat(ps[1]));
                    lPath.moveTo(lastPoint.x, lastPoint.y);
                }
                break;
                case 'l':
                case 'L': {
                    String ps[] = findPoints(i);
                    lastPoint.set(Float.parseFloat(ps[0]), Float.parseFloat(ps[1]));
                    lPath.lineTo(lastPoint.x, lastPoint.y);
                }
                break;
                case 'h':
                case 'H': {//基于上個(gè)坐標(biāo)在水平方向上劃線吻谋,因此y軸不變
                    String ps[] = findPoints(i);
                    lastPoint.set(Float.parseFloat(ps[0]), lastPoint.y);
                    lPath.lineTo(lastPoint.x, lastPoint.y);
                }
                break;
                case 'v':
                case 'V': {//基于上個(gè)坐標(biāo)在水平方向上劃線忠蝗,因此x軸不變
                    String ps[] = findPoints(i);
                    lastPoint.set(lastPoint.x, Float.parseFloat(ps[0]));
                    lPath.lineTo(lastPoint.x, lastPoint.y);
                }
                break;
                case 'c':
                case 'C': {//3次貝塞爾曲線
                    String ps[] = findPoints(i);
                    lastPoint.set(Float.parseFloat(ps[4]), Float.parseFloat(ps[5]));
                    lPath.cubicTo(Float.parseFloat(ps[0]), Float.parseFloat(ps[1]), Float.parseFloat(ps[2]), Float.parseFloat(ps[3]), Float.parseFloat(ps[4]), Float.parseFloat(ps[5]));
                }
                break;
                case 's':
                case 'S': {//一般S會(huì)跟在C或是S命令后面使用,用前一個(gè)點(diǎn)做起始控制點(diǎn)
                    String ps[] = findPoints(i);
                    lPath.cubicTo(lastPoint.x,lastPoint.y,Float.parseFloat(ps[0]), Float.parseFloat(ps[1]), Float.parseFloat(ps[2]), Float.parseFloat(ps[3]));
                    lastPoint.set(Float.parseFloat(ps[2]), Float.parseFloat(ps[3]));
                }
                break;
                case 'q':
                case 'Q': {//二次貝塞爾曲線
                    String ps[] = findPoints(i);
                    lastPoint.set(Float.parseFloat(ps[2]), Float.parseFloat(ps[3]));
                    lPath.quadTo(Float.parseFloat(ps[0]), Float.parseFloat(ps[1]), Float.parseFloat(ps[2]), Float.parseFloat(ps[3]));
                }
                break;
                case 't':
                case 'T': {//T命令會(huì)跟在Q后面使用漓拾,用Q的結(jié)束點(diǎn)做起始點(diǎn)
                    String ps[] = findPoints(i);
                    lPath.quadTo(lastPoint.x,lastPoint.y,Float.parseFloat(ps[0]), Float.parseFloat(ps[1]));
                    lastPoint.set(Float.parseFloat(ps[0]), Float.parseFloat(ps[1]));
                }
                break;
                case 'a':
                case 'A':{//畫弧
                }
                break;
                case 'z':
                case 'Z': {//結(jié)束
                    lPath.close();
                }
                break;
            }
        }
        return lPath;
    }

    private String[] findPoints(int cmdIndexInPosition) {
        int cmdIndex = cmdPositions.get(cmdIndexInPosition);
        String pointString = svgPath.substring(cmdIndex + 1, cmdPositions.get(cmdIndexInPosition + 1));
        return pointString.split(",");
    }

    private void findCommand() {
        cmdPositions.clear();
        while (mIndex < svgPathLenght) {
            char c = svgPath.charAt(mIndex);
            if ('A' <= c && c <= 'Z') {
                cmdPositions.add(mIndex);
            }else if ('a' <= c && c <= 'z') {
                cmdPositions.add(mIndex);
            }
            ++mIndex;
        }
    }
}

代碼已分享到github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末阁最,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子骇两,更是在濱河造成了極大的恐慌速种,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件低千,死亡現(xiàn)場(chǎng)離奇詭異配阵,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門棋傍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)救拉,“玉大人,你說(shuō)我怎么就攤上這事瘫拣∫谛酰” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵麸拄,是天一觀的道長(zhǎng)派昧。 經(jīng)常有香客問(wèn)我,道長(zhǎng)感帅,這世上最難降的妖魔是什么斗锭? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮失球,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘帮毁。我一直安慰自己实苞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布烈疚。 她就那樣靜靜地躺著黔牵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪爷肝。 梳的紋絲不亂的頭發(fā)上猾浦,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音灯抛,去河邊找鬼金赦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛对嚼,可吹牛的內(nèi)容都是我干的夹抗。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼纵竖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼漠烧!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起靡砌,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤已脓,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后通殃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體度液,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恨诱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片媳瞪。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖照宝,靈堂內(nèi)的尸體忽然破棺而出蛇受,到底是詐尸還是另有隱情,我是刑警寧澤厕鹃,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布兢仰,位于F島的核電站,受9級(jí)特大地震影響剂碴,放射性物質(zhì)發(fā)生泄漏把将。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一忆矛、第九天 我趴在偏房一處隱蔽的房頂上張望察蹲。 院中可真熱鬧,春花似錦催训、人聲如沸洽议。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)亚兄。三九已至,卻和暖如春采驻,著一層夾襖步出監(jiān)牢的瞬間审胚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工礼旅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留膳叨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓各淀,卻偏偏與公主長(zhǎng)得像懒鉴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子碎浇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

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