Вы можете использовать конфигурационную электронную почту с помощью 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
}
Это работает для меня!
Начиная с iOS 11, UIKit будет анимировать cornerRadius
, если вы обновите его внутри блока анимации. Просто установите layer.cornerRadius
вашего представления в блок анимации UIView
или (чтобы обрабатывать изменения ориентации интерфейса), установите его в layoutSubviews
или viewDidLayoutSubviews
.
Итак, вы хотите это:
(Я включил 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
Мой ответ был вдохновлен этим ответом Саймона .
Этот ответ основывается на более раннем ответе на 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, чтобы полностью понять это изменение.
Эти ответы на перевод обычно идут 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
Я бы предложил не использовать радиус угла, но вместо этого использовать CAShapeLayer в качестве маски для слоя контента вашего представления.
Вы установили заполненную 360-градусную дугу CGPath как форму слоя формы и установите его как маску вашего слоя.
Затем вы можете либо анимировать новое преобразование шкалы для слоя маски, либо оживить изменение радиуса пути. Оба метода должны оставаться круглыми, хотя масштабное преобразование может не дать вам чистую форму при меньших размерах пикселей.
Время было бы сложной частью (получение анимации слоя маски происходит в стоп-кадре с помощью ограниченная анимация.)
В 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), которые добавляются при ротации устройства.
CircleView
или методов, описанных в этом ответе. Я тестировал вашу версию своего кода на игровой площадке, и это сработало. В любом случае, вы должны задать свой собственный вопрос, если у вас возникнут проблемы. – rob mayoff 7 January 2017 в 05:50