Анимация изменения размера UIView с угловым радиусом [дубликат]

Вы можете использовать конфигурационную электронную почту с помощью codeigniter, например, используя smtp (простой способ):

$config = Array(
        'protocol' => 'smtp',
        'smtp_host' => 'mail.domain.com', //your smtp host
        'smtp_port' => 26, //default port smtp
        'smtp_user' => 'name@domain.com',
        'smtp_pass' => 'password',
        'mailtype' => 'html',
        'charset' => 'iso-8859-1',
        'wordwrap' => TRUE
);
$message = 'Your msg';
$this->load->library('email', $config);
$this->email->from('name@domain.com', 'Title');
$this->email->to('emaildestination@domain.com');
$this->email->subject('Header');
$this->email->message($message);

if($this->email->send()) 
{
   //conditional true
}

Это работает для меня!

12
задан rob mayoff 29 April 2016 в 16:02
поделиться

5 ответов

UPDATE: Если целью развертывания является iOS 11 или новее:

Начиная с iOS 11, UIKit будет анимировать cornerRadius, если вы обновите его внутри блока анимации. Просто установите layer.cornerRadius вашего представления в блок анимации UIView или (чтобы обрабатывать изменения ориентации интерфейса), установите его в layoutSubviews или viewDidLayoutSubviews.

ОРИГИНАЛ: Если цель развертывания старше чем iOS 11:

Итак, вы хотите это:

(Я включил Debug> Slow Animations, чтобы упростить гладкость чтобы увидеть.)

Боковое высказывание, не стесняйтесь пропустить этот абзац: это оказывается намного сложнее, чем должно быть, потому что SDK iOS не делает параметры (продолжительность, временная кривая) анимации авторотации, доступной удобным способом. Вы можете (я думаю) получить от них, переопределив -viewWillTransitionToSize:withTransitionCoordinator: на вашем контроллере просмотра, чтобы вызвать -animateAlongsideTransition:completion: на координаторе перехода, а в обратном вызове вы передадите transitionDuration и completionCurve из UIViewControllerTransitionCoordinatorContext. И тогда вам нужно передать эту информацию до вашего CircleView, который должен сохранить его (поскольку он еще не был изменен!), А позже, когда он получает layoutSubviews, он может использовать его для создания CABasicAnimation для cornerRadius с сохраненными параметрами анимации. И не случайно создавайте анимацию, когда это не анимированный размер ... End of side rant.

Ничего себе, это звучит как тонна работы, и вам нужно привлечь контроллер вида. Вот еще один подход, который полностью реализован внутри CircleView. Он работает сейчас (в iOS 9), но я не могу гарантировать, что он всегда будет работать в будущем, потому что он делает два предположения, которые теоретически могут быть ошибочными в будущем.

Вот такой подход: переопределить -actionForLayer:forKey: в CircleView, чтобы вернуть действие, которое при запуске устанавливает анимацию для cornerRadius.

Это два предположения:

  • bounds.origin и bounds.size получить отдельные анимации. (Это правда сейчас, но предположительно будущий iOS мог бы использовать одну анимацию для bounds. Было бы достаточно легко проверить анимацию bounds, если анимация bounds.size не найдена.)
  • Анимация bounds.size добавляется в слой до того, как Core Animation запросит действие cornerRadius.

Учитывая эти предположения, когда Core Animation запрашивает действие cornerRadius, мы можем получить анимацию bounds.size со слоя, скопировать ее и изменить копию для анимации cornerRadius. Копия имеет те же параметры анимации, что и оригинал (если мы не модифицируем их), поэтому она имеет правильную продолжительность и временную кривую.

Вот начало CircleView:

class CircleView: UIView {

    override func layoutSubviews() {
        super.layoutSubviews()
        updateCornerRadius()
    }

    private func updateCornerRadius() {
        layer.cornerRadius = min(bounds.width, bounds.height) / 2
    }

Обратите внимание, что границы представления задаются до того, как представление получает layoutSubviews, и поэтому перед обновлением cornerRadius. Вот почему анимация bounds.size установлена ​​перед запросом анимации cornerRadius.

Когда мы устанавливаем cornerRadius, Core Animation просит нас запустить CAAction:

    override func action(for layer: CALayer, forKey event: String) -> CAAction? {
        if event == "cornerRadius" {
            if let boundsAnimation = layer.animation(forKey: "bounds.size") as? CABasicAnimation {
                let animation = boundsAnimation.copy() as! CABasicAnimation
                animation.keyPath = "cornerRadius"
                let action = Action()
                action.pendingAnimation = animation
                action.priorCornerRadius = layer.cornerRadius
                return action
            }
        }
        return super.action(for: layer, forKey: event)
    }

В код выше, если нас попросят выполнить действие для cornerRadius, мы будем искать CABasicAnimation на bounds.size. Если мы его найдем, мы скопируем его, изменим путь ключа к cornerRadius и сохраним его в пользовательском CAAction (класса Action, который я покажу ниже). Мы также сохраняем текущее значение свойства cornerRadius, потому что Core Animation вызывает actionForLayer:forKey: перед обновлением свойства.

После возвращения actionForLayer:forKey: Core Animation обновляет свойство cornerRadius этого слоя. Затем он запускает действие, отправив его runActionForKey:object:arguments:. Задача действия - установить любую анимацию. Вот пользовательский подкласс CAAction, который я вложил внутри CircleView:

    private class Action: NSObject, CAAction {
        var pendingAnimation: CABasicAnimation?
        var priorCornerRadius: CGFloat = 0
        public func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) {
            if let layer = anObject as? CALayer, let pendingAnimation = pendingAnimation {
                if pendingAnimation.isAdditive {
                    pendingAnimation.fromValue = priorCornerRadius - layer.cornerRadius
                    pendingAnimation.toValue = 0
                } else {
                    pendingAnimation.fromValue = priorCornerRadius
                    pendingAnimation.toValue = layer.cornerRadius
                }
                layer.add(pendingAnimation, forKey: "cornerRadius")
            }
        }
    }
} // end of CircleView

Метод runActionForKey:object:arguments: устанавливает свойства fromValue и toValue анимации, а затем добавляет анимация к слою. Есть осложнение: UIKit использует «аддитивные» анимации, потому что они работают лучше, если вы запускаете другую анимацию в свойстве, в то время как более ранняя анимация все еще работает. Поэтому наше действие проверяет это.

Если анимация является аддитивной, она устанавливает fromValue на разницу между старыми и новыми угловыми радиусами и устанавливает toValue на ноль. Поскольку свойство cornerRadius уровня уже обновлено к моменту запуска анимации, добавив, что fromValue в начале анимации делает его похожим на старый угловой радиус и добавляет toValue к нулю в конце анимации делает его похожим на новый угловой радиус.

Если анимация не является аддитивной (что не происходит, если UIKit создал анимацию, насколько я знаю), то она просто устанавливает значение fromValue и toValue.

Вот весь файл для вашего удобства:

import UIKit

class CircleView: UIView {

    override func layoutSubviews() {
        super.layoutSubviews()
        updateCornerRadius()
    }

    private func updateCornerRadius() {
        layer.cornerRadius = min(bounds.width, bounds.height) / 2
    }

    override func action(for layer: CALayer, forKey event: String) -> CAAction? {
        if event == "cornerRadius" {
            if let boundsAnimation = layer.animation(forKey: "bounds.size") as? CABasicAnimation {
                let animation = boundsAnimation.copy() as! CABasicAnimation
                animation.keyPath = "cornerRadius"
                let action = Action()
                action.pendingAnimation = animation
                action.priorCornerRadius = layer.cornerRadius
                return action
            }
        }
        return super.action(for: layer, forKey: event)
    }

    private class Action: NSObject, CAAction {
        var pendingAnimation: CABasicAnimation?
        var priorCornerRadius: CGFloat = 0
        public func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) {
            if let layer = anObject as? CALayer, let pendingAnimation = pendingAnimation {
                if pendingAnimation.isAdditive {
                    pendingAnimation.fromValue = priorCornerRadius - layer.cornerRadius
                    pendingAnimation.toValue = 0
                } else {
                    pendingAnimation.fromValue = priorCornerRadius
                    pendingAnimation.toValue = layer.cornerRadius
                }
                layer.add(pendingAnimation, forKey: "cornerRadius")
            }
        }
    }
} // end of CircleView

Мой ответ был вдохновлен этим ответом Саймона .

37
ответ дан rob mayoff 23 August 2018 в 02:18
поделиться
  • 1
    Благодаря! Вы должны отпустить это как Cocoa Pod. :) – Ben Guild 1 March 2016 в 05:22
  • 2
    Благодаря @sethmr для преобразования этого в Swift 3. – rob mayoff 6 January 2017 в 22:56
  • 3
    @robmayoff Я не мог заставить его работать для моих целей. Если вы посмотрите на SwiftySwitch , я пытаюсь заставить круг идеально анимировать круг. Это не выглядит плохо, как есть, но я бы не прочь заставить его работать для дальнейшего использования. Я попытался сделать tempView, который я использую для расширяющего / уменьшающего круг этого класса, и не знал, как подойти к нему дальше. – Sethmr 6 January 2017 в 23:01
  • 4
    Я быстро просмотрел ваш проект, но я не вижу никакого использования CircleView или методов, описанных в этом ответе. Я тестировал вашу версию своего кода на игровой площадке, и это сработало. В любом случае, вы должны задать свой собственный вопрос, если у вас возникнут проблемы. – rob mayoff 7 January 2017 в 05:50
  • 5
    @robmayoff Вы получили это;) – Sethmr 7 January 2017 в 16:34

Этот ответ основывается на более раннем ответе на rob mayoff . В основном, я реализовал его для нашего проекта, и он отлично работал на iPhone (iOS 9 и 10), но проблема осталась на iPad (iOS 9 или 10).

Отладка, я обнаружил, что if оператор:

if let boundsAnimation = layer.animation(forKey: "bounds.size") as? CABasicAnimation {

всегда проигрывал iPad. Похоже, анимации построены в другой последовательности на iPad, чем iPhone. Оглядываясь на исходный ответ Саймона , кажется, что секвенирование изменилось раньше. Поэтому я объединил оба ответа, давая мне что-то вроде этого:

override func action(for layer: CALayer, forKey event: String) -> CAAction? {
    let buildAction: (CABasicAnimation) -> Action = { boundsAnimation in
        let animation = boundsAnimation.copy() as! CABasicAnimation
        animation.keyPath = "cornerRadius"
        let action = Action()
        action.pendingAnimation = animation
        action.priorCornerRadius = layer.cornerRadius
        return action
    }

    if event == "cornerRadius" {
        if let boundsAnimation = layer.animation(forKey: "bounds.size") as? CABasicAnimation {
            return buildAction(boundsAnimation)
        } else if let boundsAnimation = self.action(for: layer, forKey: "bounds") as? CABasicAnimation {
            return buildAction(boundsAnimation)
        }
    }

    return super.action(for: layer, forKey: event)
}

Объединив оба ответа, кажется, что он работает правильно как на iPhone, так и на iPad под iOS 9 и 10. Я еще не тестировал дальше, и не знаю достаточно о CoreAnimation, чтобы полностью понять это изменение.

2
ответ дан Community 23 August 2018 в 02:18
поделиться
  • 1
    К сожалению, теперь это похоже на новую версию IOS версии 10.3, анимация снова квадратизирована. У кого-нибудь есть идеи для этого. – Daniel Brotherston 3 April 2017 в 14:09

Эти ответы на перевод обычно идут Objective-c ==> Swift, но в случае, если у вас остались более упрямые авторы Objective-c, вот ответ @ Rob перевел ...

// see https://stackoverflow.com/a/35714554/294949

#import "RoundView.h"

@interface Action : NSObject<CAAction>
@property(strong,nonatomic) CABasicAnimation *pendingAnimation;
@property(assign,nonatomic) CGFloat priorCornerRadius;
@end

@implementation Action
- (void)runActionForKey:(NSString *)event object:(id)anObject
              arguments:(nullable NSDictionary *)dict {

    if ([anObject isKindOfClass:[CALayer self]]) {
        CALayer *layer = (CALayer *)anObject;
        if (self.pendingAnimation.isAdditive) {
            self.pendingAnimation.fromValue = @(self.priorCornerRadius - layer.cornerRadius);
            self.pendingAnimation.toValue = @(0);
        } else {
            self.pendingAnimation.fromValue = @(self.priorCornerRadius);
            self.pendingAnimation.toValue = @(layer.cornerRadius);
        }
        [layer addAnimation:self.pendingAnimation forKey:@"cornerRadius"];
    }
}
@end

@interface RoundView ()
@property(weak,nonatomic) UIImageView *imageView;
@end

@implementation RoundView

- (void)layoutSubviews {
    [super layoutSubviews];
    [self updateCornerRadius];
}

- (void)updateCornerRadius {
    self.layer.cornerRadius = MIN(self.bounds.size.width, self.bounds.size.height)/2.0;
}

- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event {
    if ([event isEqualToString:@"cornerRadius"]) {
        CABasicAnimation *boundsAnimation = (CABasicAnimation *)[self.layer animationForKey:@"bounds.size"];
        CABasicAnimation *animation = [boundsAnimation copy];
        animation.keyPath = @"cornerRadius";
        Action *action = [[Action alloc] init];
        action.pendingAnimation = animation;
        action.priorCornerRadius = layer.cornerRadius;
        return action;
    }
    return [super actionForLayer:layer forKey:event];;
}

@end
0
ответ дан danh 23 August 2018 в 02:18
поделиться

Я бы предложил не использовать радиус угла, но вместо этого использовать CAShapeLayer в качестве маски для слоя контента вашего представления.

Вы установили заполненную 360-градусную дугу CGPath как форму слоя формы и установите его как маску вашего слоя.

Затем вы можете либо анимировать новое преобразование шкалы для слоя маски, либо оживить изменение радиуса пути. Оба метода должны оставаться круглыми, хотя масштабное преобразование может не дать вам чистую форму при меньших размерах пикселей.

Время было бы сложной частью (получение анимации слоя маски происходит в стоп-кадре с помощью ограниченная анимация.)

-1
ответ дан Duncan C 23 August 2018 в 02:18
поделиться
  • 1
    Правильно, поэтому на самом деле это не решает проблему. Я согласен с использованием CAShapeLayer, поскольку маска - лучший подход, но жесткое кодирование, соответствующее задержке анимации изменения размера / вращения, на самом деле не похоже на хорошую стратегию. – Ben Guild 1 March 2016 в 03:16

В iOS 10 вам не нужно создавать CAAction, он просто создает CABasicAnimation и предоставляет это в вашем действии (для слоя :, для ключа :) -> CAAction? (см. пример Swift):

private var currentBoundsAnimation: CABasicAnimation? {
    return layer.animation(forKey: "bounds.size") as? CABasicAnimation ?? layer.animation(forKey: "bounds") as? CABasicAnimation
}

override public var bounds: CGRect {
    didSet {
        layer.cornerRadius = min(bounds.width, bounds.height) / 2
    }
}

override public func action(for layer: CALayer, forKey event: String) -> CAAction? {
    if(event == "cornerRadius"), let boundsAnimation = currentBoundsAnimation {
        let animation = CABasicAnimation(keyPath: "cornerRadius")
        animation.duration = boundsAnimation.duration
        animation.timingFunction = boundsAnimation.timingFunction
        return animation
    }

    return super.action(for: layer, forKey: event)
}

Вместо переопределения свойства bounds вы также можете переопределить layoutSubviews:

override func layoutSubviews() {
    super.layoutSubviews()
    layer.cornerRadius = min(bounds.width, bounds.height) / 2
}

Это работает магически, потому что CABasicAnimation указывает на отсутствие и значениям из уровня модели и представления. Чтобы правильно настроить время, вам нужно личное свойство currentBoundsAnimation, чтобы получить текущие анимации («границы» для iPad и «bounds.size» для iPhone), которые добавляются при ротации устройства.

1
ответ дан user2782993 23 August 2018 в 02:18
поделиться
Другие вопросы по тегам:

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