17
17
void * _myObserverContextB = (void *)20175282 ;
18
18
void * _myObserverContextC = (void *)20175283 ;
19
19
20
+ CGFloat _myMyLayoutScale = 1.0 ;
21
+ CGFloat _myMLayoutSizeError = 0.0 ;
20
22
21
23
@implementation UIView (MyLayoutExt)
22
24
25
+ +(void )load
26
+ {
27
+ _myMyLayoutScale = [UIScreen mainScreen ].scale ;
28
+ _myMLayoutSizeError = (1.0 / _myMyLayoutScale + 0.0001 ); // 误差增量。
29
+ }
30
+
23
31
24
32
-(MyLayoutPos*)topPos
25
33
{
@@ -1257,7 +1265,7 @@ -(CGRect)estimateLayoutRect:(CGSize)size inSizeClass:(MySizeClass)sizeClass sbs:
1257
1265
if (self.cacheEstimatedRect )
1258
1266
_useCacheRects = YES ;
1259
1267
1260
- return CGRectMake (0 , 0 , selfSize.width , selfSize.height );
1268
+ return CGRectMake (0 , 0 , _myRoundNumber ( selfSize.width ), _myRoundNumber ( selfSize.height ) );
1261
1269
}
1262
1270
1263
1271
// 只获取计算得到尺寸,不进行真正的布局。
@@ -1374,7 +1382,7 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(UIView*)object chan
1374
1382
// 只监控父视图的尺寸变换
1375
1383
CGRect rcOld = [change[NSKeyValueChangeOldKey ] CGRectValue ];
1376
1384
CGRect rcNew = [change[NSKeyValueChangeNewKey ] CGRectValue ];
1377
- if (!CGSizeEqualToSize (rcOld.size , rcNew.size ))
1385
+ if (!_myCGSizeEqual (rcOld.size , rcNew.size ))
1378
1386
{
1379
1387
[self myUpdateLayoutRectInNoLayoutSuperview: object];
1380
1388
}
@@ -1789,6 +1797,7 @@ -(void)layoutSubviews
1789
1797
{
1790
1798
newSelfSize = [self calcLayoutRect: [self myCalcSizeInNoLayoutSuperview: self .superview currentSize: oldSelfSize] isEstimate: NO pHasSubLayout: nil sizeClass: sizeClass sbs: nil ];
1791
1799
}
1800
+ newSelfSize = _myRoundSize (newSelfSize);
1792
1801
_useCacheRects = NO ;
1793
1802
1794
1803
// 设置子视图的frame并还原
@@ -1811,21 +1820,24 @@ -(void)layoutSubviews
1811
1820
}
1812
1821
1813
1822
// 这里的位置需要进行有效像素的舍入处理,否则可能出现文本框模糊,以及视图显示可能多出一条黑线的问题。
1814
- CGRect rc = sbvmyFrame.frame ;
1815
- if (![sbv isKindOfClass: [MyBaseLayout class ]])
1823
+ // 原因是当frame中的值不能有效的转化为最小可绘制的物理像素时就会出现模糊,虚化,多出黑线,以及layer处理圆角不圆的情况。
1824
+ // 所以这里要将frame中的点转化为有效的点。
1825
+ // 这里之所以讲布局子视图的转化方法和一般子视图的转化方法区分开来是因为。我们要保证布局子视图不能出现细微的重叠,因为布局子视图有边界线
1826
+ // 如果有边界线而又出现细微重叠的话,那么边界线将无法正常显示,因此这里做了一个特殊的处理。
1827
+ CGRect rc;
1828
+ if ([sbv isKindOfClass: [MyBaseLayout class ]])
1816
1829
{
1817
- rc = _myRoundRect (rc);
1818
- }
1819
-
1820
- if (CGAffineTransformIsIdentity (sbv.transform ))
1821
- {
1822
- sbv.frame = rc;
1830
+ rc = _myRoundRectForLayout (sbvmyFrame.frame );
1823
1831
}
1824
1832
else
1825
1833
{
1826
- sbv.center = CGPointMake (rc.origin .x + sbv.layer .anchorPoint .x * rc.size .width , rc.origin .y + sbv.layer .anchorPoint .y * rc.size .height );
1827
- sbv.bounds = CGRectMake (ptorigin.x , ptorigin.y , rc.size .width , rc.size .height );
1834
+ rc = _myRoundRect (sbvmyFrame.frame );
1828
1835
}
1836
+
1837
+
1838
+ sbv.center = CGPointMake (rc.origin .x + sbv.layer .anchorPoint .x * rc.size .width , rc.origin .y + sbv.layer .anchorPoint .y * rc.size .height );
1839
+ sbv.bounds = CGRectMake (ptorigin.x , ptorigin.y , rc.size .width , rc.size .height );
1840
+
1829
1841
1830
1842
}
1831
1843
@@ -1846,9 +1858,15 @@ -(void)layoutSubviews
1846
1858
[sbvmyFrame reset ];
1847
1859
}
1848
1860
1849
- // 调整自身
1850
- if (! CGSizeEqualToSize (oldSelfSize, newSelfSize) && newSelfSize .width != CGFLOAT_MAX)
1861
+
1862
+ if (newSelfSize.width != CGFLOAT_MAX && (lsc. wrapContentWidth || lsc. wrapContentHeight ) )
1851
1863
{
1864
+
1865
+ // 因为布局子视图的新老尺寸计算在上面有两种不同的方法,因此这里需要考虑两种计算的误差值,而这两种计算的误差值是不超过1/屏幕精度的。
1866
+ // 因此我们认为当二者的值超过误差时我们才认为有尺寸变化。
1867
+ BOOL isWidthAlter = fabs (newSelfSize.width - oldSelfSize.width ) > _myMLayoutSizeError;
1868
+ BOOL isHeightAlter = fabs (newSelfSize.height - oldSelfSize.height ) > _myMLayoutSizeError;
1869
+
1852
1870
// 如果父视图也是布局视图,并且自己隐藏则不调整自身的尺寸和位置。
1853
1871
BOOL isAdjustSelf = YES ;
1854
1872
if (self.superview != nil && [self .superview isKindOfClass: [MyBaseLayout class ]])
@@ -1857,7 +1875,7 @@ -(void)layoutSubviews
1857
1875
if ([supl myIsNoLayoutSubview: self ])
1858
1876
isAdjustSelf = NO ;
1859
1877
}
1860
- if (isAdjustSelf)
1878
+ if (isAdjustSelf && (isWidthAlter || isHeightAlter) )
1861
1879
{
1862
1880
1863
1881
if (newSelfSize.width < 0 )
@@ -1872,13 +1890,36 @@ -(void)layoutSubviews
1872
1890
1873
1891
if (CGAffineTransformIsIdentity (self.transform ))
1874
1892
{
1875
- self.frame = CGRectMake (self.frame .origin .x , self.frame .origin .y , newSelfSize.width , newSelfSize.height );
1893
+ CGRect currentFrame = self.frame ;
1894
+ if (isWidthAlter && lsc.wrapContentWidth )
1895
+ currentFrame.size .width = newSelfSize.width ;
1896
+
1897
+ if (isHeightAlter && lsc.wrapContentHeight )
1898
+ currentFrame.size .height = newSelfSize.height ;
1899
+
1900
+ self.frame = currentFrame;
1876
1901
}
1877
1902
else
1878
1903
{
1879
- self.bounds = CGRectMake (self.bounds .origin .x , self.bounds .origin .y , newSelfSize.width , newSelfSize.height );
1880
- self.center = CGPointMake (self.center .x + (newSelfSize.width - oldSelfSize.width ) * self.layer .anchorPoint .x , self.center .y + (newSelfSize.height - oldSelfSize.height ) * self.layer .anchorPoint .y );
1881
- }
1904
+ CGRect currentBounds = self.bounds ;
1905
+ CGPoint currentCenter = self.center ;
1906
+
1907
+ if (isWidthAlter && lsc.wrapContentWidth )
1908
+ {
1909
+ currentBounds.size .width = newSelfSize.width ;
1910
+ currentCenter.x += (newSelfSize.width - oldSelfSize.width ) * self.layer .anchorPoint .x ;
1911
+ }
1912
+
1913
+ if (isHeightAlter && lsc.wrapContentHeight )
1914
+ {
1915
+ currentBounds.size .height = newSelfSize.height ;
1916
+ currentCenter.y += (newSelfSize.height - oldSelfSize.height ) * self.layer .anchorPoint .y ;
1917
+ }
1918
+
1919
+ self.bounds = currentBounds;
1920
+ self.center = currentCenter;
1921
+
1922
+ }
1882
1923
}
1883
1924
}
1884
1925
@@ -1933,7 +1974,7 @@ -(void)layoutSubviews
1933
1974
centerPonintSelf.x = rectSuper.size .width - centerPonintSelf.x ;
1934
1975
1935
1976
// 如果有变化则只调整自己的center。而不变化
1936
- if (!CGPointEqualToPoint (self.center , centerPonintSelf))
1977
+ if (!_myCGPointEqual (self.center , centerPonintSelf))
1937
1978
{
1938
1979
self.center = centerPonintSelf;
1939
1980
}
@@ -1963,7 +2004,7 @@ -(void)layoutSubviews
1963
2004
superCenter.x += (superBounds.size .width - supv.bounds .size .width ) * supv.layer .anchorPoint .x ;
1964
2005
}
1965
2006
1966
- if (!CGRectEqualToRect (supv.bounds , superBounds))
2007
+ if (!_myCGRectEqual (supv.bounds , superBounds))
1967
2008
{
1968
2009
supv.center = superCenter;
1969
2010
supv.bounds = superBounds;
@@ -2434,7 +2475,8 @@ -(BOOL)myUpdateLayoutRectInNoLayoutSuperview:(UIView*)newSuperview
2434
2475
if ([MyBaseLayout isRTL ])
2435
2476
rectSelf.origin .x = rectSuper.size .width - rectSelf.origin .x - rectSelf.size .width ;
2436
2477
2437
- if (!CGRectEqualToRect (rectSelf, oldRectSelf))
2478
+ rectSelf = _myRoundRect (rectSelf);
2479
+ if (!_myCGRectEqual (rectSelf, oldRectSelf))
2438
2480
{
2439
2481
if (rectSelf.size .width < 0 )
2440
2482
{
@@ -3339,6 +3381,7 @@ -(void)layoutSublayersOfLayer:(CAShapeLayer *)layer
3339
3381
layerRect = CGRectMake (self.bottomBorderline .headIndent , layoutSize.height - self.bottomBorderline .thick / scale - self.bottomBorderline .offset , layoutSize.width - self.bottomBorderline .headIndent - self.bottomBorderline .tailIndent , self.bottomBorderline .thick /scale);
3340
3382
fromPoint = CGPointMake (0 , 0 );
3341
3383
toPoint = CGPointMake (layerRect.size .width , 0 );
3384
+
3342
3385
}
3343
3386
else
3344
3387
{
@@ -3354,7 +3397,9 @@ -(void)layoutSublayersOfLayer:(CAShapeLayer *)layer
3354
3397
}
3355
3398
3356
3399
// 把动画效果取消。
3357
- if (!CGRectEqualToRect (layer.frame , layerRect))
3400
+
3401
+
3402
+ if (!_myCGRectEqual (layer.frame , layerRect))
3358
3403
{
3359
3404
if (layer.lineDashPhase == 0 )
3360
3405
{
@@ -3500,28 +3545,76 @@ BOOL _myCGFloatGreatOrEqual(CGFloat f1, CGFloat f2)
3500
3545
#endif
3501
3546
}
3502
3547
3548
+ BOOL _myCGSizeEqual (CGSize sz1, CGSize sz2)
3549
+ {
3550
+ return _myCGFloatEqual (sz1.width , sz2.width ) && _myCGFloatEqual (sz1.height , sz2.height );
3551
+ }
3552
+
3553
+ BOOL _myCGPointEqual (CGPoint pt1, CGPoint pt2)
3554
+ {
3555
+ return _myCGFloatEqual (pt1.x , pt2.x ) && _myCGFloatEqual (pt1.y , pt2.y );
3556
+ }
3557
+
3558
+ BOOL _myCGRectEqual (CGRect rect1, CGRect rect2)
3559
+ {
3560
+ return _myCGSizeEqual (rect1.size , rect2.size ) && _myCGPointEqual (rect1.origin , rect2.origin );
3561
+ }
3562
+
3563
+
3503
3564
CGFloat _myRoundNumber (CGFloat f)
3504
3565
{
3505
- if (f == CGFLOAT_MAX)
3566
+ if (f == 0 || f == CGFLOAT_MAX || f == - CGFLOAT_MAX)
3506
3567
return f;
3507
3568
3508
- static CGFloat scale;
3509
- scale = [UIScreen mainScreen ].scale ;
3510
- static CGFloat inc;
3511
- inc = 0.5 /scale;
3569
+ int fi = (int )f;
3570
+ if (f == fi)
3571
+ return fi;
3572
+
3573
+ // 按精度四舍五入
3574
+ // 正确的算法应该是。x = 0; y = 0; 0<x<0.5 y = 0; x = 0.5 y = 0.5; 0.5<x<1 y = 0.5; x=1 y = 1;
3512
3575
3513
- f += inc;
3514
- f *= scale;
3515
- return floor (f) / scale;
3576
+ if (f < 0 )
3577
+ {
3578
+ return ceil (f * _myMyLayoutScale) / _myMyLayoutScale;
3579
+ }
3580
+ else
3581
+ {
3582
+ return floor (f *_myMyLayoutScale) / _myMyLayoutScale;
3583
+ }
3584
+
3516
3585
}
3517
3586
3587
+ CGRect _myRoundRectForLayout (CGRect rect)
3588
+ {
3589
+ CGFloat x1 = rect.origin .x ;
3590
+ CGFloat y1 = rect.origin .y ;
3591
+ CGFloat w1 = rect.size .width ;
3592
+ CGFloat h1 = rect.size .height ;
3593
+
3594
+ rect.origin .x = _myRoundNumber (x1);
3595
+ rect.origin .y = _myRoundNumber (y1 );
3596
+
3597
+ CGFloat mx = _myRoundNumber (x1 + w1);
3598
+ CGFloat my = _myRoundNumber (y1 + h1);
3599
+
3600
+ rect.size .width = mx - rect.origin .x ;
3601
+ rect.size .height = my - rect.origin .y ;
3602
+
3603
+ return rect;
3604
+
3605
+ }
3606
+
3607
+
3608
+
3518
3609
CGRect _myRoundRect (CGRect rect)
3519
3610
{
3520
- rect.origin .x = _myRoundNumber (rect.origin .x );
3611
+ rect.origin .x = _myRoundNumber (rect.origin .x );
3521
3612
rect.origin .y = _myRoundNumber (rect.origin .y );
3522
3613
rect.size .width = _myRoundNumber (rect.size .width );
3523
3614
rect.size .height = _myRoundNumber (rect.size .height );
3615
+
3524
3616
return rect;
3617
+
3525
3618
}
3526
3619
3527
3620
CGSize _myRoundSize (CGSize size)
0 commit comments