ios - 如何在 iOS 中制作如下图所示的仪表视图?
问题描述
我看过像 gaugekit 这样的库,但它们并没有解决我的问题。是否有任何其他库可以制作图像中的仪表视图?如果没有,那我该如何解决呢?
正如@DonMag 指出的那样。我试图通过在仪表视图顶部添加一个视图来对仪表套件进行更改......但结果并不好。
所以我坚持在实际仪表之间留出空间。
解决方案
I suggest you create your own custom view, it's not so difficult. Here is how I would do it. I have left out some details for clarity, but you can see in the comments my suggested solutions for that.
First, create a sub-class of UIVew
. We will need one property to keep track of the gauge position. This goes into your .h file.
@interface GaugeView : UIView
@property (nonatomic) CGFloat knobPosition;
@end
Next, add the implementation. The GaugeView is a view in itself, so it will be used as the container for the other parts we want. I have used awakeFromNib
function to do the initialization, so that you can use the class for a UIView in Storyboard. If you prefer, you can do the initialization from an init
function also.
I have not provided code for the knob in the center, but I would suggest you simply create one view with a white disc (or two to make the gray circle) and the labels to hold the texts parts, and beneath that you add an image view with the gray pointer. The pointer can be moved by applying a rotational transform it.
- (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;
}
Next, create the segments. The actual shapes are not added here, since they will require the size of the view. It is better to defer that to 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];
}
}
Next, we need to respond to size changes to the view. This is where we create the actual shapes too.
- (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
// :
}
Then we need the shapes.
- (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;
}
Finally, we want to respond to changes to the knobPosition
property. Calling setNeedsLayout
will trigger a call to 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];
}
This is what it will look like now. Add the knob, some colors and possibly different sized segments and you are done!
推荐阅读
- hyperledger-fabric - 使用 Java SDK 创建创世块和通道配置事务
- struct - Julia:跨不同结构实例的字段应用函数
- ros - ROS中Joy主题的订阅者
- flutter - Flutter BLoC 模式未来
.then 不是基于存储库网络结果的触发器 - statistics - SPSS:如何在spss中找到两个变量之间的关系
- reactjs - 反应编辑表
- amazon-web-services - AWS CLI 过滤器以返回特定 AMI 名称的最新 AMI 的唯一列表
- javascript - Slick Carousel:幻灯片在具有动态宽度的网格子项内不是全宽
- reactjs - 使用 Material UI 选项卡作为链接的 React Router
- azure-devops - 查询给定日期之后的需求描述更改