草庐IT

ios - 使 UIImage 在@IB_Designable 上的新位置重绘

coder 2024-01-23 原文

我正在创建这个 IB_Designable 类。它就像一个 slider 。见图片。这两个元素都是用很少可拉伸(stretch)的 UIImages 创建的。

我有一个 66x66 pt 的红色方 block 。这个正方形必须在灰色矩形内的 X 方向上滑动。

我已经创建了这个类:

标题

#import <UIKit/UIKit.h>

IB_DESIGNABLE

@interface MyClass : UIView

// minimum and maximum slider value
@property (assign, nonatomic) IBInspectable CGFloat minimumValue;
@property (assign, nonatomic) IBInspectable CGFloat maximumValue;

@property (assign, nonatomic) IBInspectable CGFloat value;

@end

实现

#import "MyClass.h"

@interface MyClass() {
  __weak IBOutlet UIView *topContainer;
  CGFloat minimumThumbCoordinate;
  CGFloat maximumThumbCoordinate;
}

@property (weak, nonatomic) IBOutlet UIImageView *thumb;

@end


@implementation MyClass



- (void)awakeFromNib {
  [super awakeFromNib];

  // topContainer contains everything
  CGRect topContainerBounds = [topContainer bounds];
  CGRect thumbBounds = [self.thumb bounds];

  CGFloat topContainerWidth = CGRectGetWidth(topContainerBounds);
  CGFloat thumbWidth = CGRectGetWidth(thumbBounds);

  minimumThumbCoordinate = floorf(thumbWidth / 2.0f);
  maximumThumbCoordinate = floorf(topContainerWidth - minimumThumbCoordinate);

}

-(void)setValue:(CGFloat)value {

  if ((value < self.minimumValue) || (value > self.maximumValue)) return;

  // normalize values

  CGFloat minimumValueNormalized = self.minimumValue;
  CGFloat maximumValueNormalized = self.maximumValue;
  CGFloat desiredValue = value;

  if ((minimumValueNormalized < 0) && (maximumValueNormalized > 0)) {
    CGFloat absoluteMinimum = fabsf(self.minimumValue);
    minimumValueNormalized = 0;
    maximumValueNormalized += absoluteMinimum;
    desiredValue += absoluteMinimum;
  }

  CGFloat percentage = desiredValue/maximumValueNormalized;

  // find coordinate
  CGFloat coordinateRange = maximumThumbCoordinate - minimumThumbCoordinate;
CGFloat relativeCoordinate = percentage * coordinateRange;

CGPoint center = CGPointMake(relativeCoordinate, self.thumb.center.y);

  [self.thumb setCenter: center];

}

问题是,当我在界面生成器上设置值时,setValue 方法不会让拇指移动……有什么想法吗?

最佳答案

您不能在 Storyboard中添加缩略图的组件。在这种情况下,我怀疑您的 thumb image view outlet 在 IB 中预览时为 nil,因此可能不会更改 value更新任何 subview 。

您通常通过以编程方式添加 subview 来解决这个问题,例如像这样的东西:

//  MyClass.h

#import <UIKit/UIKit.h>

IB_DESIGNABLE
@interface MyClass : UIView

@property (nonatomic, strong) IBInspectable UIImage *thumbnailImage;

@property (nonatomic) IBInspectable CGFloat minimumValue;
@property (nonatomic) IBInspectable CGFloat maximumValue;

@property (nonatomic) IBInspectable CGFloat value;
@property (nonatomic, readonly) CGFloat percent;

@end

//  MyClass.m

#import "MyClass.h"

@interface MyClass ()

@property (weak, nonatomic) UIImageView *thumbnailView;
@property (nonatomic) CGFloat thumbWidth;

@end

@implementation MyClass

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

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

- (void)configureView {
    UIImageView *thumb = [[UIImageView alloc] initWithImage:self.thumbnailImage];
    [self addSubview:thumb];
    thumb.backgroundColor = [UIColor lightGrayColor]; // in case no image has been set
    thumb.clipsToBounds = true;                       // in case you change your `contentMode`
    thumb.contentMode = UIViewContentModeScaleToFill;
    _thumbnailView = thumb;

    _thumbWidth = 44;                                 // maybe you have another IBInspectable property for this...

    [self layoutThumbnail];
}

- (void)setThumbnailImage:(UIImage *)image {
    self.thumbnailView.image = image;
}

- (CGFloat)percent {
    CGFloat range = self.maximumValue - self.minimumValue;
    return range ? (self.value - self.minimumValue) / range : 0;
}

- (void)layoutSubviews {
    [super layoutSubviews];

    [self layoutThumbnail];
}

- (void)layoutThumbnail {
    CGFloat minX = self.thumbWidth / 2;
    CGFloat maxX = self.bounds.size.width - self.thumbWidth / 2;

    CGRect frame = CGRectMake(self.percent * (maxX - minX) + minX - self.thumbWidth / 2, 0, self.thumbWidth, self.bounds.size.height);

    self.thumbnailView.frame = frame;
}

- (void)setValue:(CGFloat)value {
    if (value < self.minimumValue)
        _value = self.minimumValue;
    else if (value > self.maximumValue) {
        _value = self.maximumValue;
    } else {
        _value = value;
    }

    [self layoutThumbnail];
}

@end

请注意,我不仅会在您更改值时更新缩略图框,还会在 layoutSubviews 时更新。如果您的控件在运行时更改大小(例如,用户旋转设备并且控件更改大小),您希望确保缩略图框架更新。我还将缩略图图像设为一个属性,因此如果您愿意,您也可以在 IB 中设置它。但也许您使用了一些硬编码/默认图像。我还认为我们用于布置缩略图的 percent 可能对使用该控件的代码有用,因此我公开了该属性。

现在,你正在使用 ImageView ,但如果你想要的只是主控件和缩略图的圆角,我不会使用图像,而只是圆化 layer 用于适当的 UIView 对象。另外,我不清楚你对某些事情的意图(例如,我不确定你的 topContainer 指的是什么......你通常不会引用可设计 View 的 View 层次结构之外的 View ).并且您将顶层 View 引用为 ImageView ,如果您也想要那里的背景图像,您会这样做。

但这些细节与您的更广泛的问题无关。希望这能说明这个想法,如果您以编程方式创建 subview ,您可以看到缩略图在您更改 IBInspectable value 时移动。


我在这里看到了一些实现,人们想要定义带有 socket 的可设计 View 的所有 View 层次结构。但在那种情况下,您对所有这些 subview 都有一个独立的 NIB。如果您在 StackOverflow 中搜索“IBDesignable NIB”,您将看到指向相关答案的链接。

关于ios - 使 UIImage 在@IB_Designable 上的新位置重绘,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40456814/

有关ios - 使 UIImage 在@IB_Designable 上的新位置重绘的更多相关文章

  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 文件 IO 定界符? - 2

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

  6. 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使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  7. ruby - 在 Ruby 中创建按公共(public)键值分组的新哈希 - 2

    假设我有一个在Ruby中看起来像这样的哈希:{:ie0=>"Hi",:ex0=>"Hey",:eg0=>"Howdy",:ie1=>"Hello",:ex1=>"Greetings",:eg1=>"Goodday"}有什么好的方法可以将它变成如下内容:{"0"=>{"ie"=>"Hi","ex"=>"Hey","eg"=>"Howdy"},"1"=>{"ie"=>"Hello","ex"=>"Greetings","eg"=>"Goodday"}} 最佳答案 您要求一个好的方法来做到这一点,所以答案是:一种您或同事可以在六个月后理解

  8. ruby - 正则表达式在哪个位置失败? - 2

    我需要一个非常简单的字符串验证器来显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到与表达式相对应的字符串停止的位置,但我找不到可以做到这一点的方法。(这一定是一种相当简单的方法……也许没有?)例如,如果我有正则表达式:/^Q+E+R+$/带字符串:"QQQQEEE2ER"期望的结果应该是7 最佳答案 一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组编写它:^(Q+(E+(R+($)?)?)?)?然后你只需要计算你获得的捕获组的数量就可以知道正则表达式引擎在模式中停止的位置,你可以确定匹配结束

  9. 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

  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上

随机推荐