草庐IT

图片上的iOS线测量

coder 2023-09-24 原文

我需要一些帮助才能开始绘制两端带有圆圈的线并测量其长度。我能够划清界线,但不能让它移动,花了几个小时决定在 SO 上发帖。

所以请看下图并指导我开始。任何使用 objective-c 的示例或教程都会有所帮助。

谢谢 :)

最佳答案

这个想法看起来很有趣,所以我在 Xcode 中开始了一个新项目并创建了一个概念验证。

LineView(UIView子类)

这个类负责绘制两个圆和一条连接它们中心的线。

class LineView: UIView {

    var startPoint: CGPoint?
    var endPoint: CGPoint?

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.setup()
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setup()
    }

    private func setup() {
        self.backgroundColor = UIColor.clearColor()
        self.multipleTouchEnabled = true
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.updatePointsWithTouches(touches)
    }

    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.updatePointsWithTouches(touches)
    }

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.clearPoints()
    }

    override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
        self.clearPoints()
    }

    private func updatePointsWithTouches(touches: Set<UITouch>) {
        if touches.count >= 1 {
            self.startPoint = touches[advance(touches.startIndex, 0)].locationInView(self)
        }

        if touches.count >= 2 {
            self.endPoint = touches[advance(touches.startIndex, 1)].locationInView(self)
        }

        self.setNeedsDisplay()
    }

    private func clearPoints() {
        self.startPoint = nil
        self.endPoint = nil
        self.setNeedsDisplay()
    }



    // MARK: - Drawing

    override func drawRect(rect: CGRect) {
        // draw circle at startPoint
        if let sp = self.startPoint {
            self.drawTouchCircleAtPoint(sp)
        }

        // draw circle at endPoint
        if let ep = self.endPoint {
            self.drawTouchCircleAtPoint(ep)
        }

        // draw line between points
        if let sp = self.startPoint, ep = self.endPoint {
            self.drawLineBetweenFirstPoint(sp, secondPoint: ep)
        }
    }

    private func drawTouchCircleAtPoint(p: CGPoint) {
        let context = UIGraphicsGetCurrentContext()
        CGContextSaveGState(context)

        CGContextSetLineWidth(context, 2.0)
        CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.6)

        CGContextAddArc(context, p.x, p.y, CGFloat(30.0), CGFloat(0.0), CGFloat(M_PI * 2), 1)
        CGContextFillPath(context)

        CGContextRestoreGState(context)
    }

    private func drawLineBetweenFirstPoint(p1: CGPoint, secondPoint p2: CGPoint) {
        let context = UIGraphicsGetCurrentContext()
        CGContextSaveGState(context)

        CGContextSetStrokeColorWithColor(context, UIColor.whiteColor().colorWithAlphaComponent(0.6).CGColor)
        CGContextSetLineWidth(context, 1.0)

        CGContextMoveToPoint(context, p1.x, p1.y)
        CGContextAddLineToPoint(context, p2.x, p2.y)
        CGContextStrokePath(context)

        CGContextRestoreGState(context)
    }
}

此类引入了两个私有(private)属性:startPointendPoint,它们跟踪用户手指触摸 View 的位置。

在这个类中,您会发现一个从所有初始化程序调用的 setup() 函数。 self.multipleTouchEnabled = true 在这里至关重要,因此 View 可以同时检测到多个触摸。

touchesBegan/Moved/Ended/Cancelled 函数调用辅助函数,提取 touches 集中 UITouch 实例的位置。

最后,最后三个函数负责绘制圆和连接线。

InteractiveImageView(UIImageView 子类)

class InteractiveImageView: UIImageView {

    private var lineView: LineView!

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setup()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.setup()
    }

    private func setup() {
        self.userInteractionEnabled = true
        self.lineView = LineView(frame: self.bounds)
        self.addSubview(self.lineView)
    }

}

这个 UIImageView 子类有一个嵌入的 LineView 来捕获多点触摸事件。


您也可以将这些类与 Storyboard 一起使用!只需拖出一个 UIImageView,将其类更改为 InteractiveImageView,设置适当的约束,然后运行该应用程序。我会留给您在圆心之间的轴上绘制文本。

这是我的概念验证图片。


对于寻求Objective-C解决方案的人,请参阅下面的LineViewInteractiveImageView实现文件。

LineView(在 Objective-C 中)

#import "LineView.h"

@interface LineView ()

@property (nonatomic) CGPoint startPoint;
@property (nonatomic) CGPoint endPoint;

@end

@implementation LineView

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self setup];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
        [self setup];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)setup
{
    self.backgroundColor = [UIColor clearColor];
    self.multipleTouchEnabled = true;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self updatePointsWithTouches:touches];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self updatePointsWithTouches:touches];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self clearPoints];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self clearPoints];
}

- (void)clearPoints
{
    self.startPoint = CGPointZero;
    self.endPoint = CGPointZero;
    [self setNeedsDisplay];
}

- (void)updatePointsWithTouches:(NSSet *)touches
{
    if (touches.count >= 1) {
        UITouch *touch = [touches allObjects][0];
        self.startPoint = [touch locationInView:self];
    }

    if (touches.count >= 2) {
        UITouch *touch = [touches allObjects][1];
        self.endPoint = [touch locationInView:self];
    }

    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect
{
    if (self.startPoint.x != 0 && self.startPoint.y != 0) {
        [self drawTouchCircleAtPoint:self.startPoint];
    }

    if (self.endPoint.x != 0 && self.endPoint.y != 0) {
        [self drawTouchCircleAtPoint:self.endPoint];
    }

    if (self.endPoint.x != 0 && self.endPoint.y != 0 &&
        self.startPoint.x != 0 && self.startPoint.y != 0) {
        [self drawLineBetweenFirstPoint:self.startPoint end:self.endPoint];
    }
}

- (void)drawLineBetweenFirstPoint:(CGPoint)startPoint end:(CGPoint)endPoint
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGContextSetStrokeColorWithColor(context, [[[UIColor whiteColor] colorWithAlphaComponent:0.6] CGColor]);
    CGContextSetLineWidth(context, 1.0);

    CGContextMoveToPoint(context, startPoint.x, startPoint.y);
    CGContextAddLineToPoint(context, endPoint.x, endPoint.y);
    CGContextStrokePath(context);
    CGContextRestoreGState(context);
}

- (void)drawTouchCircleAtPoint:(CGPoint)CirclePoint
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGContextSetLineWidth(context, 2.0);
    CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.6);

    CGContextAddArc(context, CirclePoint.x, CirclePoint.y, 30.0, 30.0,  M_PI * 2, YES);
    CGContextFillPath(context);
    CGContextRestoreGState(context);
}

@end

InteractiveImageView(在 Objective-C 中)

#import "InteractiveImageView.h"
#import "LineView.h"

@interface InteractiveImageView ()

@property (strong, nonatomic) LineView *lineView;

@end

@implementation InteractiveImageView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setup];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)setup
{
    self.userInteractionEnabled = YES;
    self.lineView = [[LineView alloc] initWithFrame:self.bounds];
    [self addSubview:self.lineView];
}

@end

关于图片上的iOS线测量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31066519/

有关图片上的iOS线测量的更多相关文章

  1. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

    我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

  2. ruby-on-rails - openshift 上的 rails 控制台 - 2

    我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新ruby​​gems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems

  3. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  4. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  5. ruby-on-rails - Ruby on Rails - 为文本区域和图片生成列 - 2

    我是Rails的新手,所以请原谅简单的问题。我正在为一家公司创建一个网站。那家公司想在网站上展示它的客户。我想让客户自己管理这个。我正在为“客户”生成一个表格,我想要的三列是:公司名称、公司描述和Logo。对于名称,我使用的是name:string但不确定如何在脚本/生成脚手架终端命令中最好地创建描述列(因为我打算将其设置为文本区域)和图片。我怀疑描述(我想成为一个文本区域)应该仍然是描述:字符串,然后以实际形式进行调整。不确定如何处理图片字段。那么……说来话长:我在脚手架命令中输入什么来生成描述和图片列? 最佳答案 对于“文本”数

  6. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  7. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  8. ruby-on-rails - Ruby - 如何从 ruby​​ 上的 .pfx 文件中提取公钥、rsa 私钥和 CA key - 2

    我有一个.pfx格式的证书,我需要使用ruby​​提取公共(public)、私有(private)和CA证书。使用shell我可以这样做:#ExtractPublicKey(askforpassword)opensslpkcs12-infile.pfx-outfile_public.pem-clcerts-nokeys#ExtractCertificateAuthorityKey(askforpassword)opensslpkcs12-infile.pfx-outfile_ca.pem-cacerts-nokeys#ExtractPrivateKey(askforpassword)o

  9. ruby - 在没有基准或时间的情况下用 Ruby 测量用户时间或系统时间 - 2

    因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实

  10. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

随机推荐