路徑布局-基于數(shù)學(xué)函數(shù)的視圖布局方法

路徑布局MyPathLayoutMyLayout布局體系中的第7種布局體系割去,在這種布局體系中您只需要提供一個坐標(biāo)軸虑粥、一個曲線函數(shù)恭金、以及視圖之間的距離這三個要素就可以構(gòu)造出來一個非诚詈兀酷炫的界面布局效果鳞仙。在了解路徑布局之前您可以看看下面幾個用路徑布局實(shí)現(xiàn)的效果實(shí)例:

路徑布局效果演示圖

曲線

在解析幾何的課程中可以知道一個一元函數(shù)可以在二維平面坐標(biāo)空間中繪制出一條對應(yīng)的幾何曲線來寇蚊。下面是幾種常見的函數(shù)的幾何曲線圖。

常見的函數(shù)曲線

一些應(yīng)用中我們能看到一些UI界面的元素總是按照某些曲線路徑來排列展示棍好,這些特殊效果能夠大大的增強(qiáng)用戶體驗(yàn)以及增強(qiáng)界面的美觀性仗岸。這些布局中視圖按照某些規(guī)則排列在某些函數(shù)曲線之上,或者說我們提供一條路徑曲線梳玫,然后子視圖按照這條路徑曲線等距離或者按照某種規(guī)則進(jìn)行排列爹梁。所以基于這種規(guī)律性,我們提出了路徑布局的概念提澎。

路徑布局MyPathLayout是MyLayout布局體系里面的其中一種視圖布局的方法姚垃,在路徑布局里面的子視圖總是按照提供的一條函數(shù)曲線和一種定位的規(guī)則進(jìn)行排列布局。 那么如何來構(gòu)造這個曲線函數(shù)盼忌,以及如何來指定這些規(guī)則呢积糯?

坐標(biāo)軸

我們知道視圖是一個矩形區(qū)域的抽象掂墓,而我們在用平面坐標(biāo)進(jìn)行曲線繪制時(shí)也是要求將自變量和因變量限制在某個區(qū)間當(dāng)中,區(qū)間也是一個矩形區(qū)域看成。因此一個視圖的區(qū)域是完全可以當(dāng)做一個平面坐標(biāo)的區(qū)域的君编。對于構(gòu)建一個平面坐標(biāo)來說,我們需要指定坐標(biāo)的原點(diǎn)在哪里川慌,同時(shí)我們還要指定坐標(biāo)中橫軸代表的是自變量還是因變量吃嘿,同時(shí)我們還要指定縱軸中的值在原點(diǎn)以上是正數(shù)還是負(fù)數(shù),同時(shí)我們還要指定函數(shù)曲線的自變量的開始和結(jié)束的取值區(qū)間來構(gòu)建有限的平面區(qū)域梦重。為了對坐標(biāo)的表征我們抽象出了一個坐標(biāo)類:

   /**
 * 坐標(biāo)軸設(shè)置類兑燥,用來描述坐標(biāo)軸的信息。一個坐標(biāo)軸具有原點(diǎn)琴拧、坐標(biāo)系類型降瞳、開始和結(jié)束點(diǎn)、坐標(biāo)軸對應(yīng)的值這四個方面的內(nèi)容蚓胸。
 */
@interface MyCoordinateSetting : NSObject


/**
 *坐標(biāo)原點(diǎn)的位置,位置是相對位置挣饥,默認(rèn)是(0,0), 假如設(shè)置為(0.5,0.5)則在視圖的中間。
 */
@property(nonatomic, assign) CGPoint origin;

/**
 * 指定是否是數(shù)學(xué)坐標(biāo)系沛膳,默認(rèn)為NO扔枫,表示繪圖坐標(biāo)系。 數(shù)學(xué)坐標(biāo)系y軸向上為正锹安,向下為負(fù)茧吊;繪圖坐標(biāo)系則反之。
 */
@property(nonatomic, assign) BOOL isMath;

/**
 *指定是否是y軸和x軸互換八毯,默認(rèn)為NO,如果設(shè)置為YES則方程提供的變量是y軸的值瞄桨,方程返回的是x軸的值话速。
 */
@property(nonatomic, assign) BOOL isReverse;


//開始位置和結(jié)束位置。如果設(shè)置為-CGFLOAT_MAX, CGFLOAT_MAX表示取值是正無窮和負(fù)無窮
@property(nonatomic, assign) CGFloat start;
@property(nonatomic, assign) CGFloat end;

-(void)reset;  //恢復(fù)默認(rèn)設(shè)置芯侥。

@end

MyCoordinateSetting就是一個對坐標(biāo)進(jìn)行抽象的類泊交,從類的定義中我們可以看出一個坐標(biāo)設(shè)定的所有元素:

  • 其中的origin用來指定坐標(biāo)的原點(diǎn)在平面區(qū)域的位置,這里的值是一個相對值柱查,默認(rèn)的(0,0)表示坐標(biāo)原點(diǎn)位于視圖平面區(qū)域的左上角廓俭,而如果您設(shè)置的值是(0.5,0.5)則表示位于視圖區(qū)域的中心點(diǎn)的位置。
  • 其中的isMath用來指定縱坐標(biāo)軸也就是y軸的值的方向唉工。在我們學(xué)習(xí)幾何課程時(shí)一般都把縱軸原點(diǎn)以上的值設(shè)定為正值研乒,而把原點(diǎn)以下的值設(shè)定為負(fù)值。而在iOS開發(fā)中則恰恰相反淋硝。因?yàn)檫@個屬性值默認(rèn)是設(shè)置為NO的雹熬,表示縱軸的值原點(diǎn)往上是負(fù)數(shù)而原點(diǎn)往下則是正數(shù)宽菜。
  • 其中的isReverse則用來指定橫軸上的值代表的是自變量還是因變量
  • 其中的start,end則用來表明坐標(biāo)軸上自變量的取值區(qū)間。如果不設(shè)置則根據(jù)坐標(biāo)原點(diǎn)設(shè)置以及視圖的尺寸自動確定竿报,因?yàn)樽鴺?biāo)軸是一個無窮大的區(qū)域铅乡,因此我們必須要限制這個區(qū)域的大小才能映射到真實(shí)的視圖矩形區(qū)域中去。

在MyPathLayout中存在一個屬性:

/**
 * 坐標(biāo)系設(shè)置烈菌,您可以調(diào)整坐標(biāo)系的各種參數(shù)來完成下列兩個方法中的坐標(biāo)到繪制的映射轉(zhuǎn)換阵幸。
 */
@property(nonatomic, strong, readonly) MyCoordinateSetting *coordinateSetting;

就是用來描述路徑布局中所使用的坐標(biāo)軸信息的,因此坐標(biāo)軸是路徑布局中的第一要素芽世。

函數(shù)

當(dāng)坐標(biāo)軸設(shè)置完成后挚赊,我們就需要指定在坐標(biāo)軸上的曲線了。我們知道在二維坐標(biāo)系中的一條曲線由無數(shù)個點(diǎn)組成捂襟,一個點(diǎn)組(x,y)分別表示x軸上的數(shù)字和y軸上的數(shù)字咬腕,這些點(diǎn)是服從某些規(guī)則來進(jìn)行排列的,而這個規(guī)則我們是可以用數(shù)學(xué)函數(shù)來描述葬荷,也就是一條曲線將對應(yīng)一個數(shù)學(xué)函數(shù)涨共。為了表示這種(x,y)點(diǎn)規(guī)則的數(shù)學(xué)函數(shù),我們可以用如下三種方式來表征:

  • 直角坐標(biāo)系方式: y = ??(x)
  • 參數(shù)方程方式: y = ??(t)宠漩,x = ??(t)
  • 極坐標(biāo)系方式: r = ??(??)举反, y = r * sin(??),x = r * cos(??)

具體用那種方式來描述平面坐標(biāo)點(diǎn)扒吁,則可以根據(jù)具體的需要以及情況火鼻。在路徑布局MyPathLayout中我們可以提供上面三種方程的表示:

/**
 * 直角坐標(biāo)普通方程,x是坐標(biāo)系里面x軸的位置雕崩,返回y = f(x)魁索。要求函數(shù)在定義域內(nèi)是連續(xù)的,否則結(jié)果不確定盼铁。如果返回的y無效則函數(shù)要返回NAN
 */
@property(nonatomic, copy) CGFloat (^rectangularEquation)(CGFloat x);


/**
 *直角坐標(biāo)參數(shù)方程粗蔚,t是參數(shù), 返回CGPoint是x軸和y軸的值饶火。要求函數(shù)在定義域內(nèi)是連續(xù)的鹏控,否則結(jié)果不確定。如果返回的點(diǎn)無效肤寝,則請返回CGPointMake(NAN,NAN)
 */
@property(nonatomic, copy) CGPoint (^parametricEquation)(CGFloat t);

/**
 *極坐標(biāo)方程当辐,angle是極坐標(biāo)的弧度,返回r半徑鲤看。要求函數(shù)在定義域內(nèi)是連續(xù)的缘揪,否則結(jié)果不確定。如果返回的點(diǎn)無效,則請返回NAN
 */
@property(nonatomic, copy) CGFloat (^polarEquation)(CGFloat angle);

上面的rectangularEquation, parametricEquation, polarEquation分別用來表示直角坐標(biāo)方程函數(shù)寺晌,參數(shù)方程函數(shù)世吨,以及極坐標(biāo)方程函數(shù)∩胝鳎可以看出三者都是以block方式存在耘婚。因此我們只需要在block中實(shí)現(xiàn)不同的函數(shù)體即可。不同的函數(shù)體意味著不同的方程陆赋,在路徑布局中一個時(shí)刻只能有一種函數(shù)生效沐祷。從上面提供的三個屬性中我們可以得出如下規(guī)約:

  1. 每種函數(shù)中如果返回NAN則表示在這個定義域內(nèi)或者值域內(nèi)是無值的,也就是函數(shù)通過返回NAN來描述不連續(xù)性攒岛。
  2. 對于直角坐標(biāo)方程函數(shù)來說x的值的區(qū)間由MyCoordinateSetting中的start和end來指定赖临,默認(rèn)步長是1,如果不指定開始和結(jié)束區(qū)間默認(rèn)就是布局視圖的尺寸作為區(qū)間灾锯。
  3. 對于參數(shù)方程函數(shù)來說t的值的區(qū)間由MyCoordinateSetting中的start和end來指定兢榨,默認(rèn)步長是1,如果不指定開始和結(jié)束區(qū)間默認(rèn)就是布局視圖的尺寸作為區(qū)間顺饮。函數(shù)返回的一定是一個CGPoint型分別表示x和y吵聪。
  4. 對于極坐標(biāo)方程函數(shù)來說angle的值是弧度值,其區(qū)間由MyCoordinateSetting中的start和end來指定兼雄,默認(rèn)步長是1度吟逝。如果不指定則默認(rèn)是0到2??。

下面是一些常見函數(shù)的例子:

 //直線函數(shù) y = a *x + b;     
 pathLayout.rectangularEquation = ^(CGFloat x)
 {
      return 2 * x + 3;
 };
        
 //正玄函數(shù) y = a* sin(x);
 pathLayout.rectangularEquation = ^(CGFloat x)
 {
     return (CGFloat)(100 * sin(x / 180.0 * M_PI));
 };
       
 //擺線函數(shù), 用參數(shù)方程: x = a * (t - sin(t); y = a *(1 - cos(t));
 pathLayout.parametricEquation = ^(CGFloat t)
 {
      CGFloat t2 = t / 180 * M_PI;  //角度轉(zhuǎn)化為弧度赦肋。
      CGFloat a = 50;
      return CGPointMake(a * (t2 - sin(t2)), a * (1 - cos(t2)));            
};
       
//阿基米德螺旋線函數(shù): r = a * θ   用的是極坐標(biāo)块攒。 pathLayout.polarEquation = ^(CGFloat angle)
{
   return 20 * angle;
};

//心形線 r = a *(1 + cos(θ)
pathLayout.polarEquation = ^(CGFloat angle)
{
    return (CGFloat)(120 * (1 + cos(angle)));
};

 //星型線 x = a * cos^3(θ); y =a * sin^3(θ);
pathLayout.parametricEquation = ^(CGFloat t)
{            
    return CGPointMake(150 * pow(cos(t / 180 * M_PI),3), 150 * pow(sin(t / 180 * M_PI),3));
 };

距離

當(dāng)一個路徑布局中的坐標(biāo)和曲線函數(shù)都確定好了以后,接下來就需要確定布局中的子視圖按照什么規(guī)則來進(jìn)行排列布局了佃乘。我們知道函數(shù)曲線是一個連續(xù)的曲線囱井,我們的子視圖將根據(jù)添加的順序沿著這條曲線依次排列。一般的情況下是希望里面的子視圖的中心點(diǎn)在曲線上等距離排列趣避。而且目前路徑布局也只是支持了這種等距離排列的機(jī)制琅绅。需要注意的是這個等距離并不是兩個子視圖中心點(diǎn)之間的直線距離而是曲線距離。為此我們提供了一個路徑距離的類MyPathSpace鹅巍。這個類用來描述子視圖之間的路徑距離的類型。他的定義如下:

/**
 *子視圖之間的路徑距離類料祠,描述子視圖在路徑上的間隔距離的類型骆捧。
 */
@interface MyPathSpace : NSObject

/**浮動距離,根據(jù)布局視圖的尺寸和子視圖的數(shù)量動態(tài)決定*/
+(id)flexed;

/**固定距離髓绽,len為長度敛苇,每個子視圖之間的距離都是len*/
+(id)fixed:(CGFloat)len;

/**數(shù)量距離,根據(jù)布局視圖的尺寸和指定的數(shù)量count動態(tài)決定。*/
+(id)count:(NSInteger)count;

@end

可以看出MyPathSpace路徑距離可以支持三種類型的距離:

  • flexed 浮動距離枫攀,這個距離將會根據(jù)布局視圖的尺寸和添加的子視圖的數(shù)量來動態(tài)計(jì)算括饶。也就是說子視圖之間的距離會隨著數(shù)量的增加和被壓縮減少。
  • fixed 固定距離来涨,這個表示無論添加多少子視圖图焰,子視圖之間的距離總是一個固定的數(shù)字。
  • count 數(shù)量距離蹦掐,這個值表示的是子視圖之間的距離總是按照在一定布局尺寸并且某個具體的數(shù)量下決定的技羔。flexed和count的區(qū)別是前者根據(jù)所有的子視圖數(shù)量來動態(tài)計(jì)算間距,而后者則是根據(jù)指定的子視圖數(shù)量來靜態(tài)計(jì)算間距卧抗。

在路徑布局中提供了一個如下的屬性來指定布局中的子視圖距離類型:

/**
 *設(shè)置子視圖在路徑曲線上的距離的類型,一共有Flexed, Fixed, MaxCount,默認(rèn)是Flexed,
 */
@property(nonatomic, strong) MyPathSpace *spaceType;

通過上面的三要素:坐標(biāo)藤滥、函數(shù)、距離我們就可以很簡單的完成路徑布局的工作了社裆,你后續(xù)需要做的只是指定要添加到路徑布局的子視圖的尺寸就可以了拙绊,至于位置則會根據(jù)你所指定的三要素自動按照添加的順序進(jìn)行排列了。

路徑布局MyPathLayout中的各種方法和屬性

1. 原點(diǎn)視圖

在實(shí)踐中我們還存在一種場景就是希望某個視圖排列在坐標(biāo)區(qū)域的中心原點(diǎn)泳秀,而不是排列在曲線上标沪,這也是可以實(shí)現(xiàn)的,我們可以通過如下屬性:

/**
 *設(shè)置和獲取布局視圖中的原點(diǎn)視圖晶默,默認(rèn)是nil谨娜。如果設(shè)置了原點(diǎn)視圖則總會將原點(diǎn)視圖作為布局視圖中的最后一個子視圖。原點(diǎn)視圖將會顯示在路徑的坐標(biāo)原點(diǎn)中心上磺陡,因此原點(diǎn)布局是不會參與在路徑中的布局的趴梢。因?yàn)橹行脑c(diǎn)視圖是布局視圖中的最后一個子視圖,而MyPathLayout重寫了AddSubview方法币他,因此可以正常的使用這個方法來添加子視圖坞靶。
 */
@property(nonatomic, strong) UIView *originView;

來設(shè)置原點(diǎn)視圖,設(shè)置的原點(diǎn)視圖將不會參與到路徑曲線的排列中去蝴悉,而是放置在坐標(biāo)軸的原點(diǎn)區(qū)域位置彰阴。原點(diǎn)視圖是一個可選的子視圖,具體則需要根據(jù)界面的需求而設(shè)定拍冠。因?yàn)樵c(diǎn)視圖也是布局視圖的一個子視圖尿这,因此當(dāng)我們用subviews方法時(shí)得到的將是所有子視圖,而我們只想要那些排列在路徑曲線中的子視圖(除中心原點(diǎn)視圖)時(shí)則可以用如下屬性獲得:

/**
 *返回布局視圖中所有在曲線路徑中排列的子視圖庆杜。如果設(shè)置了原點(diǎn)視圖則返回subviews里面除最后一個子視圖外的所有子視圖射众,如果沒有原點(diǎn)子視圖則返回subviews
 */
@property(nonatomic, strong,readonly) NSArray *pathSubviews;

2. 得到路徑布局中某個子視圖的位置的自變量。

使用路徑布局的目的是我們可以建立一些酷炫的布局效果晃财,如果我們能夠附加一些動畫效果的話叨橱,那結(jié)果就更加美觀了。既然路徑布局是子視圖沿著曲線點(diǎn)來布局的,那如果我們能夠取得這些曲線點(diǎn)的信息的話罗洗,就可以用他來構(gòu)建一些關(guān)鍵幀動畫KeyFrame Animation或者Core Animation中的一些特效愉舔。

前面介紹了我們通過三種方程來構(gòu)建函數(shù),那么有時(shí)候我們希望知道某個子視圖布局的那個點(diǎn)的自變量的值伙菜。舉例來說轩缤,假如我們用極坐標(biāo)構(gòu)建了一個半徑為20的圓函數(shù) :r = 20, 然后子視圖之間的間距我們設(shè)置為flexed仇让。同時(shí)假如我添加了N個子視圖典奉,現(xiàn)在我想知道某個子視圖在圓路徑布局所處的角度值。那么這時(shí)候我們就可以通過如下方法來獲取了:

/**
 得到子視圖在曲線路徑中定位時(shí)的函數(shù)的自變量的值丧叽。也就是說在函數(shù)中當(dāng)值等于下面的返回值時(shí)卫玖,這個視圖的位置就被確定了。方法如果返回NAN則表示這個子視圖沒有定位踊淳。
 @param subview 指定的子視圖
 @return 返回指定子視圖在曲線路徑中的自變量值
 */
-(CGFloat)argumentFrom:(UIView*)subview;

這個方法的入?yún)⑹悄硞€路徑布局中的子視圖假瞬,而返回則是這個子視圖在路徑布局函數(shù)中的變量值。就上面的例子來說迂尝,他所表示的就是某個子視圖在圓上的角度脱茉。因此我們可以通過這個返回值來做一些子視圖角度旋轉(zhuǎn)的坐標(biāo)變換(通過視圖的transform屬性來實(shí)現(xiàn))÷⒖或者角度變化動畫效果等琴许。

3. 獲取兩個子視圖之間的路徑坐標(biāo)點(diǎn)信息。

有時(shí)候我們需要得到布局視圖里面兩個子視圖之間的所有曲線路徑點(diǎn)坐標(biāo)溉躲,這樣我們可以很方便的做一些幀動畫來實(shí)現(xiàn)一些特殊效果榜田。這時(shí)候可以通過下面三個方法來完成:

/**
 下面三個函數(shù)用來獲取兩個子視圖之間的曲線路徑數(shù)據(jù),在調(diào)用getSubviewPathPoint方法之前請先調(diào)用beginSubviewPathPoint方法锻梳,而調(diào)用完畢后請調(diào)用endSubviewPathPoint方法箭券,否則getSubviewPathPoint返回的結(jié)果未可知。
 */

/**
 開始獲取子視圖路徑數(shù)據(jù)的方法
 @param full 表示getSubviewPathPoint獲取的是否是全部路徑點(diǎn)疑枯。如果為NO則只會獲取子視圖的位置的點(diǎn)
 */
-(void)beginSubviewPathPoint:(BOOL)full;
/**
 結(jié)束獲取子視圖路徑數(shù)據(jù)的方法
 */
-(void)endSubviewPathPoint;

/**
 創(chuàng)建從某個子視圖到另外一個子視圖之間的路徑點(diǎn)辩块,返回NSValue數(shù)組,里面的值是CGPoint荆永。
 @param fromIndex 指定開始的子視圖的索引位置
 @param toIndex 指定結(jié)束的子視圖的索引位置废亭。如果有原點(diǎn)子視圖時(shí),這兩個索引值不能算上原點(diǎn)子視圖的索引值。
 @return 返回fromIndex到toIndex之間的所有曲線路徑點(diǎn)數(shù)組
 */
-(NSArray<NSValue*>*)getSubviewPathPoint:(NSInteger)fromIndex toIndex:(NSInteger)toIndex;

在獲取兩個子視圖之間的路徑點(diǎn)數(shù)組之前具钥,為了加速性能上處理豆村,我們需要調(diào)用beginSubviewPathPoint方法,然后再調(diào)用getSubviewPathPoint方法氓拼,最后不再需要路徑點(diǎn)時(shí)需要調(diào)用endSubviewPathPoint方法來釋放一些內(nèi)存。beginSubviewPathPoint方法中的full參數(shù)表明緩存的點(diǎn)是所有的路徑上的點(diǎn)還是所有子視圖的點(diǎn)。getSubviewPathPoint方法可以得到任意兩個在路徑上的子視圖之間的所有路徑點(diǎn)數(shù)組桃漾,路徑點(diǎn)是一個CGPoint型坏匪。為了存儲在NSArray上,系統(tǒng)把CGPoint型轉(zhuǎn)化為了NSValue型來處理撬统。這幾個方法的使用具體可以參考PLTest1ViewController里面的介紹适滓。

4.獲取函數(shù)曲線路徑。

既然路徑布局是子視圖在一條路徑曲線上排列恋追,那么就應(yīng)該有方法能夠得到這條路徑凭迹,這可以通過如下方法:

/**
 創(chuàng)建布局的曲線的路徑。用戶需要負(fù)責(zé)銷毀返回的值苦囱。調(diào)用者可以用這個方法來獲得曲線的路徑嗅绸,進(jìn)行一些繪制的工作。
 @param subviewCount 指定這個路徑上子視圖的數(shù)量的個數(shù)撕彤,如果設(shè)置為-1則是按照布局視圖的子視圖的數(shù)量來創(chuàng)建鱼鸠。需要注意的是如果布局視圖的spaceType為Flexed,Count的話則這個參數(shù)設(shè)置無效。
 @return 返回指定數(shù)量的子視圖的曲線路徑羹铅,用戶需要負(fù)責(zé)銷毀返回的對象蚀狰。
 */
-(CGPathRef)createPath:(NSInteger)subviewCount;

來得到一個曲線路徑對象,需要注意的是你應(yīng)該負(fù)責(zé)銷毀這個方法返回的對象职员。這樣你就可以通過得到的曲線路徑對象來進(jìn)行一些曲線的繪制了麻蹋,通過曲線的繪制以及布局里面子視圖的結(jié)合,就能夠得到一些非常有趣的效果焊切。另外一個方案是因?yàn)槊總€視圖都有一個layerClass屬性扮授,路徑布局也不例外,因此你可以建立一個MyPathLayout的派生類蛛蒙,并重載其中的layerClass方法如下:

//構(gòu)建一個路徑布局的派生類糙箍。
@interface MyXXXPathLayout:MyPathLayout

@end

@implementation MyXXXPathLayout
+(Class)layerClass
 {
 return [CAShapeLayer class];
 }

-(id)init
{
    self = [super init];
    if (self != nil)
    {
        CAShapeLayer *shapeLayer = (CAShapeLayer*)self.layer;
        shapeLayer.strokeColor = [UIColor redColor].CGColor;
        shapeLayer.lineWidth = 2;
        shapeLayer.fillColor = nil;  //您可以在這里設(shè)置路徑曲線的顏色、大小牵祟、填充方案等等深夯。  
    }
    
    return self;
}


@end

你需要重載layerClass 并返回一個CAShapeLayer。同時(shí)你可以在你的派生類里面設(shè)置CAShapeLayer的各種屬性诺苹,這樣你的布局視圖里面將會出現(xiàn)一條你所設(shè)置的函數(shù)的路徑曲線來咕晋。具體實(shí)現(xiàn)請參考:PLTest2ViewController

5.路徑布局子視圖之間的距離誤差。

在路徑布局中子視圖之間的距離并不是直線的等間距收奔,而是曲線的等間距掌呜,因此這里就涉及到了如何保證曲線等間距的問題。我們知道高等數(shù)學(xué)里面的微積分中有介紹坪哄,要想獲得一條曲線之間兩點(diǎn)之間的長度可以通過如下方法得到质蕉。

曲線兩點(diǎn)之間的長度

在實(shí)現(xiàn)時(shí)因?yàn)閿?shù)學(xué)庫里面并沒有對應(yīng)的積分函數(shù)势篡,而積分的本質(zhì)是小區(qū)域累加,因此MyPathLayout中為了實(shí)現(xiàn)視圖之間的等距離也是用了積分累計(jì)的方式來計(jì)算曲線長度的模暗。這樣在計(jì)算時(shí)當(dāng)累加的步長設(shè)的越小禁悠,那么等距離將是越精確,否則可能會產(chǎn)生一些距離誤差兑宇,因此我們提供了下面這個屬性:

/**
  設(shè)置獲取子視圖距離的誤差值碍侦。默認(rèn)是0.5,誤差越小則距離的精確值越大隶糕,誤差最低值不能<=0瓷产。一般不需要調(diào)整這個值,只有那些要求精度非常高的場景才需要微調(diào)這個值,比如在一些曲線路徑較短的情況下枚驻,通過調(diào)小這個值來子視圖之間間距的精確計(jì)算濒旦。
 */
@property(nonatomic, assign) CGFloat distanceError;

用來設(shè)置我們在計(jì)算時(shí)允許的距離誤差值。這個誤差值不能設(shè)置為0测秸,而且值越小疤估,誤差也越小,當(dāng)然也更加消耗計(jì)算性能霎冯。因此這里默認(rèn)設(shè)置為0.5 铃拇。這個屬性的應(yīng)用主要是用在哪些區(qū)域小而子視圖數(shù)量多的場景里面,具體可以參考:PLTest4ViewController中的例子沈撞。

總結(jié)

路徑布局的知識已經(jīng)介紹完畢慷荔。在界面布局時(shí)我們除了能用路徑布局外MyLayout布局體系還分別提供了線性布局、相對布局缠俺、表格布局显晶、框架布局、流式布局壹士、浮動布局一共七種布局磷雇,在我的簡書里面都有對各種布局進(jìn)行介紹的文檔。具體要使用那種布局來進(jìn)行界面布局躏救,就需要具體的根據(jù)你的需求和界面效果圖來完成唯笙。總之遇到問題盒使,歡迎大家及時(shí)找我交流和解答使碾。


最后歡迎大家訪問我的github站點(diǎn)咖驮,關(guān)注歐陽大哥2013

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末徽惋,一起剝皮案震驚了整個濱河市隔躲,隨后出現(xiàn)的幾起案子掉盅,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绍赛,死亡現(xiàn)場離奇詭異,居然都是意外死亡辑畦,警方通過查閱死者的電腦和手機(jī)惹资,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來航闺,“玉大人,你說我怎么就攤上這事猴誊×嗜校” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵懈叹,是天一觀的道長乖杠。 經(jīng)常有香客問我,道長澄成,這世上最難降的妖魔是什么胧洒? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮墨状,結(jié)果婚禮上卫漫,老公的妹妹穿的比我還像新娘。我一直安慰自己肾砂,他們只是感情好列赎,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著镐确,像睡著了一般包吝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上源葫,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天诗越,我揣著相機(jī)與錄音,去河邊找鬼息堂。 笑死嚷狞,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的储矩。 我是一名探鬼主播感耙,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼持隧!你這毒婦竟也來了即硼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤屡拨,失蹤者是張志新(化名)和其女友劉穎只酥,沒想到半個月后褥实,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡裂允,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年损离,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绝编。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡僻澎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出十饥,到底是詐尸還是另有隱情窟勃,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布逗堵,位于F島的核電站秉氧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蜒秤。R本人自食惡果不足惜汁咏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望作媚。 院中可真熱鬧攘滩,春花似錦、人聲如沸纸泡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弟灼。三九已至级解,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間田绑,已是汗流浹背勤哗。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掩驱,地道東北人芒划。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像欧穴,于是被迫代替她去往敵國和親民逼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

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