欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

iOS自動(dòng)進(jìn)行View標(biāo)記的方法詳解

 更新時(shí)間:2019年04月09日 10:55:21   作者:aron1992  
這篇文章主要給大家介紹了關(guān)于iOS自動(dòng)進(jìn)行View標(biāo)記的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對各位iOS開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

緣起

一切都源于我的上一篇博客,我寫的是一篇 UITableViewCell使用自動(dòng)布局的“最佳實(shí)踐” ,我需要給我的圖片里面的UIView元素添加上邊距的標(biāo)記,這讓我感到很為難,我覺得我得發(fā)點(diǎn)時(shí)間寫一個(gè)程序讓這個(gè)步驟自動(dòng)化,我只要一鍵就能讓我的程序自動(dòng)標(biāo)記邊距,這個(gè)比我要手動(dòng)去標(biāo)記來的酷很多不是嗎!

結(jié)果

所以,我發(fā)了點(diǎn)時(shí)間實(shí)現(xiàn)了我的想法,下面是實(shí)現(xiàn)的結(jié)果截圖:

以及代碼開源托管地址:代碼鏈接 (本地下載)

預(yù)覽圖

過去幾小時(shí)內(nèi)的想法

靜下心來整理我的想法和尋找方案,大概的整理下了一個(gè)可行性的方案以及這個(gè)方案中需要使用到的步驟,其中一些細(xì)節(jié)沒有在這個(gè)步驟中體現(xiàn)

  • 獲取水平的間距:遍歷父View的子View,獲取某個(gè)子sourceView的右邊到其他子targetView的左邊的距離,把結(jié)果保存到子targetView的入度數(shù)組中
  • 獲取垂直的間距:遍歷父View的子View,獲取某個(gè)子sourceView的下邊到其他子targetView的上邊的距離,把結(jié)果保存到子targetView的入度數(shù)組中
  • 篩選出targetView的入度數(shù)組中所以不符合的結(jié)果,刪除這些結(jié)果
  • 最終獲取到了一個(gè)需要進(jìn)行展示的結(jié)果數(shù)組,數(shù)組保存的是一系列的間距線段對象
  • 創(chuàng)建一個(gè)顯示標(biāo)記的TagView層,把結(jié)果的線段繪制在TagView上面,然后把TabView添加到父View上

代碼實(shí)現(xiàn)解析

注入測試邊框View

我的方案中所有的間距都是基于子View考慮的,所以子View和父View的邊距需要特殊的計(jì)算,可以使用在父View的旁邊添加一個(gè)物理像素的子View,最終只要處理所有這些子View,子View和父View的邊距就能得到體現(xiàn)了,不用再做多余的處理,這是一個(gè)討巧的方案。

+ (void)registerBorderTestViewWithView:(UIView*)view {
 CGFloat minWH = 1.0/[UIScreen mainScreen].scale;
 MMBorderAttachView* leftBorderView = [[MMBorderAttachView alloc] initWithFrame:CGRectMake(0, 0, minWH, view.bounds.size.height)];
 [view addSubview:leftBorderView];
 MMBorderAttachView* rightBorderView = [[MMBorderAttachView alloc] initWithFrame:CGRectMake(view.bounds.size.width-minWH, 0, minWH, view.bounds.size.height)];
 [view addSubview:rightBorderView];
 
 MMBorderAttachView* topBorderView = [[MMBorderAttachView alloc] initWithFrame:CGRectMake(0, 0, view.bounds.size.width, minWH)];
 [view addSubview:topBorderView];
 MMBorderAttachView* bottomBorderView = [[MMBorderAttachView alloc] initWithFrame:CGRectMake(0, view.bounds.size.height - minWH, view.bounds.size.width, minWH)];
 [view addSubview:bottomBorderView];
}

獲取父View的所有子View,抽象為MMFrameObject對象

NSMutableArray* viewFrameObjs = [NSMutableArray array];
 NSArray* subViews = view.subviews;
 for (UIView* subView in subViews) {
  // 過濾特殊的View,不屬于注入的View
  if (![subView conformsToProtocol:@protocol(MMAbstractView)]) {
   if (subView.alpha<0.001f) {
    continue;
   }
   
   if (subView.frame.size.height <= 2) {
    continue;
   }
  }
  
  MMFrameObject* frameObj = [[MMFrameObject alloc] init];
  frameObj.frame = subView.frame;
  frameObj.attachedView = subView;
  [viewFrameObjs addObject:frameObj];
 }

獲取View之間的間距

需要處理兩種情況:1、尋找View的右邊對應(yīng)的其他View的左邊;2、尋找View的下邊對應(yīng)的其他View的上邊,特殊滴需要處理兩者都是MMAbstractView的情況,這種不需要處理

NSMutableArray<MMLine*>* lines = [NSMutableArray array];
 for (MMFrameObject* sourceFrameObj in viewFrameObjs) {
  for (MMFrameObject* targetFrameObj in viewFrameObjs) {
   
   // 過濾特殊的View
   if ([sourceFrameObj.attachedView conformsToProtocol:@protocol(MMAbstractView)]
    && [targetFrameObj.attachedView conformsToProtocol:@protocol(MMAbstractView)]) {
    continue;
   }
   
   // 尋找View的右邊對應(yīng)的其他View的左邊
   MMLine* hLine = [self horizontalLineWithFrameObj1:sourceFrameObj frameObj2:targetFrameObj];
   if (hLine) {
    [lines addObject:hLine];
    [targetFrameObj.leftInjectedObjs addObject:hLine];
   }
   
   // 尋找View的下邊對應(yīng)的其他View的上邊
   MMLine* vLine = [self verticalLineWithFrameObj1:sourceFrameObj frameObj2:targetFrameObj];
   if (vLine) {
    [lines addObject:vLine];
    [targetFrameObj.topInjectedObjs addObject:vLine];
   }
  }
 }

獲取間距線段的實(shí)現(xiàn)

以獲取水平的間距線段為例,這種情況,只需要處理一個(gè)子View在另一個(gè)子View的右邊的情況,否則返回nil跳過。獲取水平間距線段,明顯的線段的X軸是確定的,要,只要處理好Y軸就行了,問題就抽象為了兩個(gè)線段的問題,這部分是在approperiatePointWithInternal方法中處理的,主要步驟是一長的線段為標(biāo)準(zhǔn),然后枚舉短的線段和長的線段存在的5種情況,相應(yīng)的計(jì)算合適的值,然后給Y軸使用。

兩條線段的5種關(guān)系

+ (MMLine*)horizontalLineWithFrameObj1:(MMFrameObject*)frameObj1 frameObj2:(MMFrameObject*)frameObj2 {
 if (ABS(frameObj1.frame.origin.x - frameObj2.frame.origin.x) < 3) {
  return nil;
 }
 
 // frameObj2整體在frameObj1右邊
 if (frameObj1.frame.origin.x + frameObj1.frame.size.width >= frameObj2.frame.origin.x) {
  return nil;
 }
 
 CGFloat obj1RightX = frameObj1.frame.origin.x + frameObj1.frame.size.width;
 CGFloat obj1Height = frameObj1.frame.size.height;
 
 CGFloat obj2LeftX = frameObj2.frame.origin.x;
 CGFloat obj2Height = frameObj2.frame.size.height;
 
 CGFloat handle = 0;
 CGFloat pointY = [self approperiatePointWithInternal:[[MMInterval alloc] initWithStart:frameObj1.frame.origin.y length:obj1Height] internal2:[[MMInterval alloc] initWithStart:frameObj2.frame.origin.y length:obj2Height] handle:&handle];
 
 MMLine* line = [[MMLine alloc] initWithPoint1:[[MMShortPoint alloc] initWithX:obj1RightX y:pointY handle:handle] point2:[[MMShortPoint alloc] initWithX:obj2LeftX y:pointY handle:handle]];
 
 return line;
}

+ (CGFloat)approperiatePointWithInternal:(MMInterval*)internal1 internal2:(MMInterval*)internal2 handle:(CGFloat*)handle {
 CGFloat MINHandleValue = 20;
 CGFloat pointValue = 0;
 CGFloat handleValue = 0;
 MMInterval* bigInternal;
 MMInterval* smallInternal;
 if (internal1.length > internal2.length) {
  bigInternal = internal1;
  smallInternal = internal2;
 } else {
  bigInternal = internal2;
  smallInternal = internal1;
 }
 
 // 線段分割法
 if (smallInternal.start < bigInternal.start && smallInternal.start+smallInternal.length < bigInternal.start) {
  CGFloat tmpHandleValue = bigInternal.start - smallInternal.start+smallInternal.length;
  pointValue = bigInternal.start - tmpHandleValue/2;
  handleValue = MAX(tmpHandleValue, MINHandleValue);
 }
 if (smallInternal.start < bigInternal.start && smallInternal.start+smallInternal.length >= bigInternal.start) {
  CGFloat tmpHandleValue = smallInternal.start+smallInternal.length - bigInternal.start;
  pointValue = bigInternal.start + tmpHandleValue/2;
  handleValue = MAX(tmpHandleValue, MINHandleValue);
 }
 if (smallInternal.start >= bigInternal.start && smallInternal.start+smallInternal.length <= bigInternal.start+bigInternal.length) {
  CGFloat tmpHandleValue = smallInternal.length;
  pointValue = smallInternal.start + tmpHandleValue/2;
  handleValue = MAX(tmpHandleValue, MINHandleValue);
 }
 if (smallInternal.start >= bigInternal.start && smallInternal.start+smallInternal.length > bigInternal.start+bigInternal.length) {
  CGFloat tmpHandleValue = bigInternal.start+bigInternal.length - smallInternal.start;
  pointValue = bigInternal.start + tmpHandleValue/2;
  handleValue = MAX(tmpHandleValue, MINHandleValue);
 }
 if (smallInternal.start >= bigInternal.start+bigInternal.length && smallInternal.start+smallInternal.length > bigInternal.start+bigInternal.length) {
  CGFloat tmpHandleValue = smallInternal.start - (bigInternal.start+bigInternal.length);
  pointValue = smallInternal.start - tmpHandleValue/2;
  handleValue = MAX(tmpHandleValue, MINHandleValue);
 }
 
 if (handle) {
  *handle = handleValue;
 }
 
 return pointValue;
}

過濾線段

一個(gè)子View對象的入度可能有好幾個(gè),需要篩選進(jìn)行刪除,我使用的篩選策略是:以水平的間距線段為例,兩條線段的Y差值小于某個(gè)閾值,選擇線段長的那條刪除,最終獲取到了一個(gè)需要進(jìn)行展示的結(jié)果數(shù)組,數(shù)組保存的是一系列的間距線段對象

// 查找重復(fù)的射入line
 // hLine:Y的差值小于某個(gè)值,leftInjectedObjs->取最小一條
 // vLine:X的差值小于某個(gè)值,topInjectedObjs->取最小一條
 CGFloat minValue = 5;
 for (MMFrameObject* sourceFrameObj in viewFrameObjs) {
  
  {
   // 排序:Y值:從大到小
   [sourceFrameObj.leftInjectedObjs sortUsingComparator:^NSComparisonResult(MMLine* _Nonnull obj1, MMLine* _Nonnull obj2) {
    return obj1.point1.point.y > obj2.point1.point.y;
   }];
   int i = 0;
   NSLog(@"\n\n");
   MMLine* baseLine, *compareLine;
   if (sourceFrameObj.leftInjectedObjs.count) {
    baseLine = sourceFrameObj.leftInjectedObjs[i];
   }
   while (i<sourceFrameObj.leftInjectedObjs.count) {
    NSLog(@"lineWidth = %.1f == ", baseLine.lineWidth);
    if (i + 1 < sourceFrameObj.leftInjectedObjs.count) {
     compareLine = sourceFrameObj.leftInjectedObjs[i + 1];
     
     if (ABS(baseLine.point1.point.y - compareLine.point1.point.y) < minValue) {
      // 移除長的一條
      if (baseLine.lineWidth > compareLine.lineWidth) {
       [lines removeObject:baseLine];
       baseLine = compareLine;
      } else {
       [lines removeObject:compareLine];
      }
     } else {
      baseLine = compareLine;
     }
    }
    i++;
   }
  }
  
  {
   // 排序:X值從大到小
   [sourceFrameObj.topInjectedObjs sortUsingComparator:^NSComparisonResult(MMLine* _Nonnull obj1, MMLine* _Nonnull obj2) {
    return obj1.point1.point.x >
    obj2.point1.point.x;
   }];
   int j = 0;
   MMLine* baseLine, *compareLine;
   if (sourceFrameObj.topInjectedObjs.count) {
    baseLine = sourceFrameObj.topInjectedObjs[j];
   }
   while (j<sourceFrameObj.topInjectedObjs.count) {
    if (j + 1 < sourceFrameObj.topInjectedObjs.count) {
     compareLine = sourceFrameObj.topInjectedObjs[j + 1];
     
     if (ABS(baseLine.point1.point.x - compareLine.point1.point.x) < minValue) {
      // 移除長的一條
      // 移除長的一條
      if (baseLine.lineWidth > compareLine.lineWidth) {
       [lines removeObject:baseLine];
       baseLine = compareLine;
      } else {
       [lines removeObject:compareLine];
      }
     } else {
      baseLine = compareLine;
     }
    }
    j++;
   }
  }
 }

TagView 的繪制

 // 繪制View
 TaggingView* taggingView = [[TaggingView alloc] initWithFrame:view.bounds lines:lines];
 [view addSubview:taggingView];

TaggingView 在drawRect繪制線段以及線段長度的文字

//
// TaggingView.m
// AutolayoutCell
//
// Created by aron on 2017/5/27.
// Copyright © 2017年 aron. All rights reserved.
//

#import "TaggingView.h"
#import "MMTagModel.h"

@interface TaggingView ()
@property (nonatomic, strong) NSArray<MMLine*>* lines;;
@end

@implementation TaggingView

- (instancetype)initWithFrame:(CGRect)frame lines:(NSArray<MMLine*>*)lines {
 self = [super initWithFrame:frame];
 if (self) {
  self.backgroundColor = [UIColor colorWithRed:255 green:255 blue:255 alpha:0.05];
  _lines = lines;
 }
 return self;
}

- (void)drawRect:(CGRect)rect {
 [super drawRect:rect];
 //1.獲取上下文
 CGContextRef context = UIGraphicsGetCurrentContext();
 
 for (MMLine* line in _lines) {
  // 繪制線段
  CGContextSetLineWidth(context, 2.0f/[UIScreen mainScreen].scale); //線寬
  CGContextSetAllowsAntialiasing(context, true);
  CGContextSetRGBStrokeColor(context, 255.0 / 255.0, 0.0 / 255.0, 70.0 / 255.0, 1.0); //線的顏色
  CGContextBeginPath(context);
  //設(shè)置起始點(diǎn)
  CGContextMoveToPoint(context, line.point1.point.x, line.point1.point.y);
  //增加點(diǎn)
  CGContextAddLineToPoint(context, line.point2.point.x, line.point2.point.y);
  CGContextStrokePath(context);
  
  // 繪制文字
  NSString *string = [NSString stringWithFormat:@"%.0f px", line.lineWidth];
  UIFont *fount = [UIFont systemFontOfSize:7];
  CGPoint centerPoint = line.centerPoint;
  NSDictionary* attrDict = @{NSFontAttributeName : fount,
        NSForegroundColorAttributeName: [UIColor redColor],
        NSBackgroundColorAttributeName: [UIColor colorWithRed:1 green:1 blue:0 alpha:0.5f]};
  [string drawInRect:CGRectMake(centerPoint.x - 15, centerPoint.y - 6, 30, 16) withAttributes:attrDict];
 }
}

@end

以上就是我的的思路以及實(shí)現(xiàn),有什么好的建議希望可以收到issue一起交流和談?wù)摗?br />

代碼托管位置

代碼傳送門(本地下載)

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對腳本之家的支持。

相關(guān)文章

  • iOS開發(fā)之WKWebViewJavascriptBridge Xcode9中導(dǎo)致crash的解決

    iOS開發(fā)之WKWebViewJavascriptBridge Xcode9中導(dǎo)致crash的解決

    大家都知道WebViewJavascriptBridge它主要幫助我們優(yōu)雅的實(shí)現(xiàn)OC與JS的交互,下面這篇文章主要給大家介紹了關(guān)于iOS開發(fā)之WKWebViewJavascriptBridge Xcode9中導(dǎo)致crash的解決方法,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-10-10
  • IOS正則表達(dá)式之驗(yàn)證密碼身份證手機(jī)號

    IOS正則表達(dá)式之驗(yàn)證密碼身份證手機(jī)號

    這篇文章主要介紹了IOS正則表達(dá)式之驗(yàn)證密碼身份證手機(jī)號的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-10-10
  • 移動(dòng)端頁面在ios中不顯示圖片的解決方法

    移動(dòng)端頁面在ios中不顯示圖片的解決方法

    下面小編就為大家?guī)硪黄苿?dòng)端頁面在ios中不顯示圖片的解決方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-11-11
  • iOs遷至WKWebView跨過的一些坑

    iOs遷至WKWebView跨過的一些坑

    這篇文章主要給大家介紹了關(guān)于iOs遷至WKWebView跨過的一些坑,文中通過示例代碼介紹的非常詳細(xì),對各位iOS開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • IOS開發(fā)筆記整理49之詳解定位CLLocation

    IOS開發(fā)筆記整理49之詳解定位CLLocation

    在項(xiàng)目功能中有一個(gè)定位CLLocation的需求,遇到了一些知識(shí)難點(diǎn),經(jīng)過各位大俠的幫助,問題解決,特此分享供大家學(xué)習(xí),希望大家共同學(xué)習(xí)進(jìn)步
    2015-11-11
  • iOS獲取短信驗(yàn)證碼倒計(jì)時(shí)的兩種實(shí)現(xiàn)方法

    iOS獲取短信驗(yàn)證碼倒計(jì)時(shí)的兩種實(shí)現(xiàn)方法

    本篇文章主要介紹了iOS獲取短信驗(yàn)證碼倒計(jì)時(shí)的兩種實(shí)現(xiàn)方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05
  • 詳解iOS中按鈕點(diǎn)擊事件處理方式

    詳解iOS中按鈕點(diǎn)擊事件處理方式

    在iOS開發(fā)中,時(shí)常會(huì)用到按鈕,通過按鈕的點(diǎn)擊來完成界面的跳轉(zhuǎn)等功能。具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-01-01
  • iOS微信第三方登錄實(shí)例

    iOS微信第三方登錄實(shí)例

    這篇文章主要為大家詳細(xì)介紹了iOS微信第三方登錄實(shí)現(xiàn)過程,一步一步告訴大家iOS微信實(shí)現(xiàn)第三方登錄的方法,感興趣的小伙伴們可以參考一下
    2016-12-12
  • iOS開發(fā)之App主題切換解決方案完整版(Swift版)

    iOS開發(fā)之App主題切換解決方案完整版(Swift版)

    這篇文章主要為大家詳細(xì)介紹了iOS開發(fā)之App主題切換完整解決方案,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • iOS中解決Xcode9的Log日志無法輸出中文的問題小結(jié)

    iOS中解決Xcode9的Log日志無法輸出中文的問題小結(jié)

    這篇文章主要介紹了iOS中解決Xcode9的Log日志無法輸出中文的問題小結(jié),需要的朋友可以參考下
    2017-11-11

最新評論