首页 > 解决方案 > 如何在 iOS 中制作如下图所示的仪表视图?

问题描述

我看过像 gaugekit 这样的库,但它们并没有解决我的问题。是否有任何其他库可以制作图像中的仪表视图?如果没有,那我该如何解决呢?

正如@DonMag 指出的那样。我试图通过在仪表视图顶部添加一个视图来对仪表套件进行更改......但结果并不好。

所以我坚持在实际仪表之间留出空间。

https://imgur.com/Qk1EpcV

标签: iosobjective-cswiftiphonegauge

解决方案


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!

enter image description here


推荐阅读