Вопрос по objective-c, drawrect, core-graphics, calayer – Использование круглого индикатора с замаскированным изображением?

6

Я работаю над круглым индикатором прогресса для просмотра пользовательских достижений игрового центра, и у меня есть вид "ударить стену", Я борюсь с этим более двух часов и до сих пор не могу заставить его работать.

Дело в том, что мне нужен круговой индикатор выполнения, где я мог бы установить (хотя бы) изображение дорожки (заливки). Потому что мой прогресс - градиент, похожий на радугу, и я не могу достичь тех же результатов, используя только код.

Я возился с CALayers и методом drawRect, однако я нет успешно. Не могли бы вы дать мне небольшое руководство?

Вот примеры круглых индикаторов выполнения:https://github.com/donnellyk/KDGoalBar https://github.com/danielamitay/DACircularProgress

Мне просто нужно, чтобы заливка была замаскированным изображением, в зависимости от прогресса. Если бы вы могли заставить это работать так, чтобы прогресс был оживленным, это было бы действительно здорово, но я нене требуется помощь с этим :)

Спасибо ник

Я мог бы описать это неясно, извините за это - я неЯ не хочу рисовать градиент, у меня есть очень хорошая градиентная круговая заливка для индикатора выполнения, сделанного в Photoshop, и мне просто нужно его замаскировать, чтобы он заполнял индикатор выполнения. Ты знаешь, что я имею в виду? :) Dominik Hadl
Так это маскировка или рисунокрадуга» как градиент, который останавливает вас? Или это соединяет две части? David Rönnqvist

Ваш Ответ

2   ответа
1

Решение, предложенное omz, работало медленно, когда я пытался оживить собственность, поэтому я продолжал искать. Нашли отличное решение - использовать платформу Quartz Core и оболочку CADisplayLink. "Этот класс специально создан для анимации, где «Ваши данные, скорее всего, будут меняться в каждом кадре », Он пытается отправить сообщение цели каждый раз, когда что-то перерисовывается на экране " Источник

Ибиблиотека это работает таким образом.

Изменить: Но есть более эффективное решение. Анимировать маску, которая наносится на слой с изображением. Я нене знаю, почему я несделать это с самого начала. CABasicAnimation работает быстрее, чем любой пользовательский рисунок. Вот моя реализация:

class ProgressBar: UIView {
    var imageView:UIImageView!

    var maskLayer: CAShapeLayer!
    var currentValue: CGFloat = 1

    override init(frame: CGRect) {
        super.init(frame: frame)
        updateUI()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        updateUI()
    }

    func updateUI(){
        makeGradient()
        setUpMask()
    }

    func animateCircle(strokeEnd: CGFloat) {
        let oldStrokeEnd = maskLayer.strokeEnd
        maskLayer.strokeEnd = strokeEnd

        //override strokeEnd implicit animation
        let animation = CABasicAnimation(keyPath: "strokeEnd")
        animation.duration = 0.5
        animation.fromValue = oldStrokeEnd
        animation.toValue = strokeEnd
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        maskLayer.add(animation, forKey: "animateCircle")

        currentValue = strokeEnd
    }

    func setUpMask(){

        let circlePath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0, y: frame.size.height / 2.0),
                                      radius: (frame.size.width - 10)/2,
                                      startAngle: -CGFloat.pi/2,
                                      endAngle: CGFloat.pi*1.5,
                                      clockwise: true)

        maskLayer = CAShapeLayer()
        maskLayer.path = circlePath.cgPath
        maskLayer.fillColor = UIColor.clear.cgColor
        maskLayer.strokeColor = UIColor.red.cgColor
        maskLayer.lineWidth = 8.0;
        maskLayer.strokeEnd = currentValue
        maskLayer.lineCap = "round"
        imageView.layer.mask = maskLayer
    }

    func makeGradient(){
        imageView = UIImageView(image: UIImage(named: "gradientImage"))
        imageView.frame = bounds
        imageView.contentMode = .scaleAspectFill
        addSubview(imageView)
    }

}

Кстати, если вы хотите стать лучше в анимации, я предлагаю отличную книгу "IOS Core Animation: книга продвинутых технологий Ника Локвуда "

23

Вам просто нужно построить путь, который определяет область, которую нужно заполнить (например, используяCGPathAddArc), обрезать графический контекст по этому пути, используяCGContextClip а затем просто нарисуйте свое изображение.

Вот'S примерdrawRect: метод, который вы можете использовать в пользовательском представлении:

- (void)drawRect:(CGRect)rect
{
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGFloat progress = 0.7f; //This would be a property of your view
    CGFloat innerRadiusRatio = 0.5f; //Adjust as needed

    //Construct the path:
    CGMutablePathRef path = CGPathCreateMutable();
    CGFloat startAngle = -M_PI_2;
    CGFloat endAngle = -M_PI_2 + MIN(1.0f, progress) * M_PI * 2;
    CGFloat outerRadius = CGRectGetWidth(self.bounds) * 0.5f - 1.0f;
    CGFloat innerRadius = outerRadius * innerRadiusRatio;
    CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
    CGPathAddArc(path, NULL, center.x, center.y, innerRadius, startAngle, endAngle, false);
    CGPathAddArc(path, NULL, center.x, center.y, outerRadius, endAngle, startAngle, true);
    CGPathCloseSubpath(path);
    CGContextAddPath(ctx, path);
    CGPathRelease(path);

    //Draw the image, clipped to the path:
    CGContextSaveGState(ctx);
    CGContextClip(ctx);
    CGContextDrawImage(ctx, self.bounds, [[UIImage imageNamed:@"RadialProgressFill"] CGImage]);
    CGContextRestoreGState(ctx);
}

Чтобы было проще, ямы жестко запрограммировали несколько вещей -вам, очевидно, нужно добавить свойство дляprogress и позвонитьsetNeedsDisplay в сеттере. Это также предполагает, что у вас есть изображение с именемRadialProgressFill в вашем проекте.

Вот'Вот пример того, как это будет выглядеть примерно так:

Надеюсь, у вас получше фоновое изображение. ;)

отличный материал, было бы неплохо иметь его в качестве проекта GitHub Daniel
@omz это действительно полезно .. :) Sudha Tiwari
Надеюсь, таких людей будет все больше и больше - это намного больше, чем я ожидал! Большое спасибо за ваш подробный ответ - я вас наградил :) Dominik Hadl
@DominikHadl Как и где можно вызвать этот метод - (void) drawRect: (CGRect) rect Sudha Tiwari

Похожие вопросы