如何在iOS中制作如下图所示的仪表视图?
how to make a gauge view as in the following image in iOS?
我看过像 gaugekit 这样的库,但它们并没有解决我的问题。
是否有任何其他库可以像图像中那样制作仪表视图?
如果没有,那我该如何解决?
正如@DonMag 指出的那样。
我试图通过在仪表视图顶部添加一个视图来对 gaugekit 进行更改....但结果并不是很好。
所以我很难在实际仪表之间留出空间。
根据我看到的图像,最简单的解决方案可能是创建 12 张图像,然后随着图像所代表的值的增长或缩小以编程方式交换图像。
我建议您创建自己的自定义视图,这并不难。这是我会怎么做。为了清楚起见,我省略了一些细节,但您可以在评论中看到我为此建议的解决方案。
首先,创建 UIVew
的子 class。我们需要一个 属性 来跟踪仪表位置。这将进入您的 .h 文件。
@interface GaugeView : UIView
@property (nonatomic) CGFloat knobPosition;
@end
接下来,添加实现。 GaugeView 本身就是一个视图,因此它将用作我们想要的其他部分的容器。我已经使用 awakeFromNib
函数进行初始化,这样您就可以在 Storyboard 中将 class 用于 UIView。如果您愿意,也可以从 init
函数进行初始化。
我没有提供中央旋钮的代码,但我建议您只需创建一个视图,其中包含一个白色圆盘(或两个以形成灰色圆圈)和用于保存文本部分的标签,以及下方你添加一个带有灰色指针的图像视图。可以通过应用旋转变换来移动指针。
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization part could also be placed in init
[self createSegmentLayers];
// Add knob views to self
// :
// Start somewhere
self.knobPosition = 0.7;
}
接下来,创建细分。此处未添加实际形状,因为它们需要视图的大小。最好将其推迟到 layoutSubviews
.
- (void)createSegmentLayers {
for (NSInteger segment = 0; segment < 10; ++segment) {
// Create the shape layer and set fixed properties
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
// Color can be set differently for each segment
shapeLayer.strokeColor = [UIColor blueColor].CGColor;
shapeLayer.lineWidth = 1.0;
[self.layer addSublayer:shapeLayer];
}
}
接下来,我们需要响应视图的大小变化。这也是我们创建实际形状的地方。
- (void)layoutSubviews {
[super layoutSubviews];
// Dynamically create the segment paths and scale them to the current view width
NSInteger segment = 0;
for (CAShapeLayer *layer in self.layer.sublayers) {
layer.frame = self.layer.bounds;
layer.path = [self createSegmentPath:segment radius:self.bounds.size.width / 2.0].CGPath;
// If we should fill or not depends on the knob position
// Since the knobPosition's range is 0.0..1.0 we can just multiply by 10
// and compare to the segment number
layer.fillColor = segment < (_knobPosition * 10) ? layer.strokeColor : nil;
// Assume we added the segment layers first
if (++segment >= 10)
break;
}
// Move and size knob images
// :
}
然后我们需要形状。
- (UIBezierPath *)createSegmentPath:(NSInteger)segment radius:(CGFloat)radius {
UIBezierPath *path = [UIBezierPath bezierPath];
// We could also use a table with start and end angles for different segment sizes
CGFloat startAngle = segment * 21.0 + 180.0 - 12.0;
CGFloat endAngle = startAngle + 15.0;
// Draw the path, two arcs and two implicit lines
[path addArcWithCenter:CGPointMake(radius, radius) radius:0.9 * radius startAngle:DEG2RAD(startAngle) endAngle:DEG2RAD(endAngle) clockwise:YES];
[path addArcWithCenter:CGPointMake(radius, radius) radius:0.75 * radius startAngle:DEG2RAD(endAngle) endAngle:DEG2RAD(startAngle) clockwise:NO];
[path closePath];
return path;
}
最后,我们要响应knobPosition
属性的变化。调用 setNeedsLayout
将触发对 layoutSubviews
.
的调用
// Position is 0.0 .. 1.0
- (void)setKnobPosition:(CGFloat)knobPosition {
// Rotate the knob image to point at the right segment
// self.knobPointerImageView.transform = CGAffineTransformMakeRotation(DEG2RAD(knobPosition * 207.0 + 180.0));
_knobPosition = knobPosition;
[self setNeedsLayout];
}
这就是现在的样子。添加旋钮、一些颜色和可能不同大小的段,您就完成了!
我看过像 gaugekit 这样的库,但它们并没有解决我的问题。 是否有任何其他库可以像图像中那样制作仪表视图? 如果没有,那我该如何解决?
正如@DonMag 指出的那样。 我试图通过在仪表视图顶部添加一个视图来对 gaugekit 进行更改....但结果并不是很好。
所以我很难在实际仪表之间留出空间。
根据我看到的图像,最简单的解决方案可能是创建 12 张图像,然后随着图像所代表的值的增长或缩小以编程方式交换图像。
我建议您创建自己的自定义视图,这并不难。这是我会怎么做。为了清楚起见,我省略了一些细节,但您可以在评论中看到我为此建议的解决方案。
首先,创建 UIVew
的子 class。我们需要一个 属性 来跟踪仪表位置。这将进入您的 .h 文件。
@interface GaugeView : UIView
@property (nonatomic) CGFloat knobPosition;
@end
接下来,添加实现。 GaugeView 本身就是一个视图,因此它将用作我们想要的其他部分的容器。我已经使用 awakeFromNib
函数进行初始化,这样您就可以在 Storyboard 中将 class 用于 UIView。如果您愿意,也可以从 init
函数进行初始化。
我没有提供中央旋钮的代码,但我建议您只需创建一个视图,其中包含一个白色圆盘(或两个以形成灰色圆圈)和用于保存文本部分的标签,以及下方你添加一个带有灰色指针的图像视图。可以通过应用旋转变换来移动指针。
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization part could also be placed in init
[self createSegmentLayers];
// Add knob views to self
// :
// Start somewhere
self.knobPosition = 0.7;
}
接下来,创建细分。此处未添加实际形状,因为它们需要视图的大小。最好将其推迟到 layoutSubviews
.
- (void)createSegmentLayers {
for (NSInteger segment = 0; segment < 10; ++segment) {
// Create the shape layer and set fixed properties
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
// Color can be set differently for each segment
shapeLayer.strokeColor = [UIColor blueColor].CGColor;
shapeLayer.lineWidth = 1.0;
[self.layer addSublayer:shapeLayer];
}
}
接下来,我们需要响应视图的大小变化。这也是我们创建实际形状的地方。
- (void)layoutSubviews {
[super layoutSubviews];
// Dynamically create the segment paths and scale them to the current view width
NSInteger segment = 0;
for (CAShapeLayer *layer in self.layer.sublayers) {
layer.frame = self.layer.bounds;
layer.path = [self createSegmentPath:segment radius:self.bounds.size.width / 2.0].CGPath;
// If we should fill or not depends on the knob position
// Since the knobPosition's range is 0.0..1.0 we can just multiply by 10
// and compare to the segment number
layer.fillColor = segment < (_knobPosition * 10) ? layer.strokeColor : nil;
// Assume we added the segment layers first
if (++segment >= 10)
break;
}
// Move and size knob images
// :
}
然后我们需要形状。
- (UIBezierPath *)createSegmentPath:(NSInteger)segment radius:(CGFloat)radius {
UIBezierPath *path = [UIBezierPath bezierPath];
// We could also use a table with start and end angles for different segment sizes
CGFloat startAngle = segment * 21.0 + 180.0 - 12.0;
CGFloat endAngle = startAngle + 15.0;
// Draw the path, two arcs and two implicit lines
[path addArcWithCenter:CGPointMake(radius, radius) radius:0.9 * radius startAngle:DEG2RAD(startAngle) endAngle:DEG2RAD(endAngle) clockwise:YES];
[path addArcWithCenter:CGPointMake(radius, radius) radius:0.75 * radius startAngle:DEG2RAD(endAngle) endAngle:DEG2RAD(startAngle) clockwise:NO];
[path closePath];
return path;
}
最后,我们要响应knobPosition
属性的变化。调用 setNeedsLayout
将触发对 layoutSubviews
.
// Position is 0.0 .. 1.0
- (void)setKnobPosition:(CGFloat)knobPosition {
// Rotate the knob image to point at the right segment
// self.knobPointerImageView.transform = CGAffineTransformMakeRotation(DEG2RAD(knobPosition * 207.0 + 180.0));
_knobPosition = knobPosition;
[self setNeedsLayout];
}
这就是现在的样子。添加旋钮、一些颜色和可能不同大小的段,您就完成了!