iOS可以拖動(dòng)控制大小的立方體盒子

最近接到需求,要做一個(gè)可以用slider控制長(zhǎng)寬高,并且支持自適應(yīng)畫(huà)布大小的立方體盒子。

先上效果圖

截屏2021-07-01 上午11.07.08.png

需要自己建立一個(gè)立方體,然后給八個(gè)頂點(diǎn)命名。

37D5E690-FF15-4BBF-A509-B15DDE3A401B.png

我們分析一下,需要畫(huà)出來(lái)的一共有8個(gè)頂點(diǎn),3個(gè)面(里面的面如因?yàn)楸粨踝×?,所以不需要?huà)),12根邊。

為此,建立一個(gè)立方體對(duì)應(yīng)的Model,在Model中把傳入的長(zhǎng)寬高轉(zhuǎn)化為立方體的八個(gè)頂點(diǎn)的坐標(biāo)值。

側(cè)邊的邊長(zhǎng)是w的話,那么y0的值就是w/√2,y1就是長(zhǎng)L+ w/√2,然后依次算出y2、y3、z0-z3。

-(void)updateL:(CGFloat )L w:(CGFloat)w h:(CGFloat)h canvas:(CGRect)canvas {
    CGFloat geng = 0.707;// 根號(hào)2分之一
    
    self.y0 = CGPointMake(w*geng, 0); //newy0;
    self.y1 = CGPointMake(L + w *geng, 0);// newy1;
    self.y2 = CGPointMake(L, w * geng);// newy2;
    self.y3 = CGPointMake(0, w * geng);// newy3;
    self.z0 = CGPointMake( w * geng, h);// newz0;
    self.z1 = CGPointMake(L + w * geng, h) ;//newz1;
    self.z2 = CGPointMake(L, h + w * geng);// newz2;
    self.z3 = CGPointMake(0, h + w * geng);// newz3;
}

給畫(huà)筆設(shè)置顏色

    [color set];

然后先畫(huà)前面一個(gè)面:

//畫(huà)前面
    CGPoint sPoints0[4];
    sPoints0[0] = box.y3;
    sPoints0[1] = box.y2;
    sPoints0[2] = box.z2;
    sPoints0[3] = box.z3;
    CGContextAddLines(context, sPoints0, 4);//添加線
 
    [[UIColor clearColor] setStroke];//避免影響方格線
    
    CGContextClosePath(context);//封起來(lái)
    CGContextDrawPath(context, kCGPathFillStroke); //根據(jù)坐標(biāo)繪制路徑

然后同理依次畫(huà)右邊,上邊的面:

//畫(huà)右邊
    CGPoint sPoints[4];//坐標(biāo)點(diǎn)
    sPoints[0] =box.y1;//坐標(biāo)1
    sPoints[1] =box.z1;
    sPoints[2] = box.z2;
    sPoints[3] = box.y2;
    CGContextAddLines(context, sPoints, 4);//添加線
    CGContextClosePath(context);//封起來(lái)
    CGContextDrawPath(context, kCGPathFillStroke); //根據(jù)坐標(biāo)繪制路徑
    
    //畫(huà)上邊
    CGPoint sPoints2[4];//坐標(biāo)點(diǎn)
    sPoints2[0] = box.y0;
    sPoints2[1] = box.y1;
    sPoints2[2] = box.y2;
    sPoints2[3] = box.y3;
    CGContextAddLines(context, sPoints2, 4);//添加線
    CGContextClosePath(context);//封起來(lái)
    CGContextDrawPath(context, kCGPathFillStroke); //根據(jù)坐標(biāo)繪制路徑

然后再畫(huà)12條邊:

首先設(shè)置虛線的樣式

 //畫(huà)虛線
    CGFloat dashArray[] = {2, 4}; // 表示先繪制2個(gè)點(diǎn),再跳過(guò)4個(gè)點(diǎn)
    CGContextSetLineDash(context, 0, dashArray, 2); // 畫(huà)虛線

    //指定直線樣式
    CGContextSetLineCap(context, kCGLineCapSquare);
    //直線寬度
    CGContextSetLineWidth(context, 1);
    //設(shè)置顏色
    CGContextSetStrokeColorWithColor(context, lineColor.CGColor);

然后依次繪制12條邊:

 //開(kāi)始繪制
    CGContextBeginPath(context);
    //上邊
    CGContextMoveToPoint(context, box.y0.x, box.y0.y);
    CGContextAddLineToPoint(context, box.y1.x, box.y1.y);
    CGContextAddLineToPoint(context, box.y2.x, box.y2.y);
    CGContextAddLineToPoint(context, box.y3.x, box.y3.y);
    CGContextAddLineToPoint(context, box.y0.x, box.y0.y);
    //左邊
    CGContextAddLineToPoint(context, box.z0.x, box.z0.y);
    CGContextAddLineToPoint(context, box.z3.x, box.z3.y);
    CGContextAddLineToPoint(context, box.y3.x, box.y3.y);
    //下邊
    CGContextMoveToPoint(context, box.z0.x, box.z0.y);
    CGContextAddLineToPoint(context, box.z1.x, box.z1.y);
    CGContextAddLineToPoint(context, box.z2.x, box.z2.y);
    CGContextAddLineToPoint(context, box.z3.x, box.z3.y);

    //剩余的兩根
    CGContextMoveToPoint(context, box.y2.x, box.y2.y);
    CGContextAddLineToPoint(context, box.z2.x, box.z2.y);

    CGContextMoveToPoint(context, box.y1.x, box.y1.y);
    CGContextAddLineToPoint(context, box.z1.x, box.z1.y);

    //繪制完成
    CGContextStrokePath(context);

以上,就是一個(gè)立方體的繪制過(guò)程。

滑動(dòng)slider時(shí),只需要把對(duì)應(yīng)的slider的value乘以長(zhǎng)寬高的最大值,就得到每條邊的實(shí)際值。

    CGFloat l = self.maxL * self.sliderL.value;
    CGFloat w = self.maxW * self.sliderW.value;
    CGFloat h = self.maxH * self.sliderH.value;

然后更新立方體

    [self.boxView updateL:l  w:w h: h];

我們還有一個(gè)要求就是,如果立方體的任意一邊超出畫(huà)布后,需要把畫(huà)布進(jìn)行縮放以適應(yīng)整個(gè)立方體全部顯示在畫(huà)布內(nèi)。

因?yàn)槲覀兊牧⒎襟w始終在畫(huà)布的左下角,所以只需要判斷右上角有沒(méi)有超出畫(huà)布范圍就好了。(如果你們沒(méi)有要求在左下角,那只需要判斷右下角即可,總之需要把所有頂點(diǎn)都顯示出來(lái))

if (self.y1.x > canvas.size.width || self.y1.y < 0) {
        //超出畫(huà)布區(qū)域,實(shí)行縮放畫(huà)布
        
        CGFloat ratioX = self.y1.x / canvas.size.width;
        CGFloat ratioY = (canvas.size.height - self.y1.y) / canvas.size.height;
        
        CGFloat ratio = MAX(ratioX, ratioY);
        //畫(huà)布縮小到 ratio
        if (self.ratioBlock) {
            self.ratioBlock(ratio);
        }
    }

以上,基本就是全部?jī)?nèi)容。

附上代碼地址:
https://github.com/zgsddzwj/SSAnimatedBox

喜歡的話給個(gè)star吧~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容