Индикатор активности с пользовательским изображением
Я загружаю UIWebView
, и пока я не показываю пустую страницу с этим индикатором активности
(индикатор активности сири). Из того, что я понял, вы не можете изменить изображение, но не можете ли я использовать это изображение и создать анимацию с ней, вращающуюся на 360 ° и зацикливание? Или это истощает батарею?
что-то вроде этого?:
- (void)webViewDidStartLoad:(UIWebView *)webView {
//set up animation
[self.view addSubview:self.loadingImage];
//start animation
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
//stop animation
[self.loadingImage removeFromSuperview];
}
Что мне делать?
Спасибо заранее!
Ответы
Ответ 1
Большая часть этого находится в переполнении стека. Позвольте мне подвести итог:
Создайте UIImageView, который будет служить индикатором активности (внутри сцены раскадровки, NIB, код... где бы вы ни пожелали). Позвольте называть его _activityIndicatorImage
Загрузите изображение: _activityIndicatorImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"activity_indicator"]];
Вам нужно использовать анимацию, чтобы повернуть ее. Вот метод, который я использую:
+ (void)rotateLayerInfinite:(CALayer *)layer
{
CABasicAnimation *rotation;
rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
rotation.fromValue = [NSNumber numberWithFloat:0];
rotation.toValue = [NSNumber numberWithFloat:(2 * M_PI)];
rotation.duration = 0.7f; // Speed
rotation.repeatCount = HUGE_VALF; // Repeat forever. Can be a finite number.
[layer removeAllAnimations];
[layer addAnimation:rotation forKey:@"Spin"];
}
Внутри метода layoutSubviews я запускаю ротацию. Вы можете поместить это в свои webViewDidStartLoad
и webViewDidFinishLoad
, если это лучше для вашего случая:
- (void)layoutSubviews
{
[super layoutSubviews];
// some other code
[Utils rotateLayerInfinite:_activityIndicatorImage.layer];
}
Вы всегда можете остановить вращение с помощью [_activityIndicatorImage.layer removeAllAnimations];
Ответ 2
Вы можете использовать этот красивый загрузчик, вдохновленный Tumblr app:
Asich/AMTumblrHud
Ответ 3
SWIFT 4 Sweet And Просто поместите расширение UIView {}
Модифицированный ответ @gandhi Mena
если вы хотите создать свой собственный индикатор загрузки
Создайте расширение UIView, которое создает и настраивает логотип вашего бренда в качестве настраиваемого индикатора и помещает этот код в файл глобальной декларации.
extension UIView{
func customActivityIndicator(view: UIView, widthView: CGFloat?,backgroundColor: UIColor?, textColor:UIColor?, message: String?) -> UIView{
//Config UIView
self.backgroundColor = backgroundColor //Background color of your view which you want to set
var selfWidth = view.frame.width
if widthView != nil{
selfWidth = widthView ?? selfWidth
}
let selfHeigh = view.frame.height
let loopImages = UIImageView()
let imageListArray = ["image1", "image2"] // Put your desired array of images in a specific order the way you want to display animation.
loopImages.animationImages = imageListArray
loopImages.animationDuration = TimeInterval(0.8)
loopImages.startAnimating()
let imageFrameX = (selfWidth / 2) - 30
let imageFrameY = (selfHeigh / 2) - 60
var imageWidth = CGFloat(60)
var imageHeight = CGFloat(60)
if widthView != nil{
imageWidth = widthView ?? imageWidth
imageHeight = widthView ?? imageHeight
}
//ConfigureLabel
let label = UILabel()
label.textAlignment = .center
label.textColor = .gray
label.font = UIFont(name: "SFUIDisplay-Regular", size: 17.0)! // Your Desired UIFont Style and Size
label.numberOfLines = 0
label.text = message ?? ""
label.textColor = textColor ?? UIColor.clear
//Config frame of label
let labelFrameX = (selfWidth / 2) - 100
let labelFrameY = (selfHeigh / 2) - 10
let labelWidth = CGFloat(200)
let labelHeight = CGFloat(70)
// Define UIView frame
self.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width , height: UIScreen.main.bounds.size.height)
//ImageFrame
loopImages.frame = CGRect(x: imageFrameX, y: imageFrameY, width: imageWidth, height: imageHeight)
//LabelFrame
label.frame = CGRect(x: labelFrameX, y: labelFrameY, width: labelWidth, height: labelHeight)
//add loading and label to customView
self.addSubview(loopImages)
self.addSubview(label)
return self }}
Скрыть индикатор примерно так: вы можете удалить подпредставление вверху из стека подпредставлений. поместите этот код в тот же объявленный глобально файл swift.
func hideLoader(removeFrom : UIView){
removeFrom.subviews.last?.removeFromSuperview()
}
Теперь вы можете стрелять в метку по этому коду. Чтобы отобразить индикатор активности в вашем контроллере вида, введите этот код, когда вы хотите отобразить.
self.view.addSubview(UIView().customActivityIndicator(view: self.view, widthView: nil, backgroundColor:"Desired color", textColor: "Desired color", message: "Loading something"))
Чтобы скрыть загрузчик анимации, вы можете использовать вышеупомянутую функцию, которую вы определили в глобальном масштабе. В вашем ViewController.swift, где вы хотите скрыть, поместите эту строку кода.
hideLoader(removeFrom: self.view)
imageListArray выглядит следующим образом.
![enter image description here]()
![enter image description here]()
![enter image description here]()
Ответ 4
Без изображения вы можете использовать стороннюю библиотеку
для объектного C (также поддерживается в iOS 6) https://github.com/shebinkoshy/UIControllsRepo
для быстрого https://github.com/shebinkoshy/Activity-Indicator-Swift
<сильные > Преимущества
- > Возможность установки цветов для spinner
- > Доступно в разных размерах, таких как маленькие, маленькие, средние, большие, очень большие
- > Возможность установки заголовка (в центре и внизу) для средних, больших и очень больших размеров
Ответ 5
Вы можете установить изображения на activityIndicator
. Я создал функцию для добавить пользовательский образ в ActivityIndicator. Вот что я создал.
public func showProgressView(view: UIView) -> UIImageView {
let containerView = UIView()
let progressView = UIView()
var activityIndicatorImageView = UIImageView()
if let statusImage = UIImage(named: Constants.ActivityIndicatorImageName1) {
let activityImageView = UIImageView(image: statusImage)
containerView.frame = view.frame
containerView.backgroundColor = UIColor(hex: 0xffffff, alpha: 0.3)
progressView.frame = CGRectMake(0, 0, 80, 80)
progressView.center = CGPointMake(view.bounds.width / 2, view.bounds.height / 2)
progressView.backgroundColor = UIColor(hex: 0x18bda3, alpha: 0.7)
progressView.clipsToBounds = true
progressView.layer.cornerRadius = 10
activityImageView.animationImages = [UIImage(named: Constants.ActivityIndicatorImageName1)!,
UIImage(named: Constants.ActivityIndicatorImageName2)!,
UIImage(named: Constants.ActivityIndicatorImageName3)!,
UIImage(named: Constants.ActivityIndicatorImageName4)!,
UIImage(named: Constants.ActivityIndicatorImageName5)!]
activityImageView.animationDuration = 0.8;
activityImageView.frame = CGRectMake(view.frame.size.width / 2 - statusImage.size.width / 2, view.frame.size.height / 2 - statusImage.size.height / 2, 40.0, 48.0)
activityImageView.center = CGPointMake(progressView.bounds.width / 2, progressView.bounds.height / 2)
dispatch_async(dispatch_get_main_queue()) {
progressView.addSubview(activityImageView)
containerView.addSubview(progressView)
view.addSubview(containerView)
activityIndicatorImageView = activityImageView
}
}
return activityIndicatorImageView
}
Вы можете вызвать этот метод всюду в своем коде. И просто вызовите метод startAnimating
. Если вы хотите скрыть, просто вызовите метод stopAnimating
.
Ответ 6
работает как в SWITF 3, так и в 4
var activityIndicator = UIActivityIndicatorView()
var myView : UIView = UIView()
func viewDidLoad() {
spinnerCreation()
}
func spinnerCreation() {
activityIndicator.activityIndicatorViewStyle = .whiteLarge
let label = UILabel.init(frame: CGRect(x: 5, y: 60, width: 90, height: 20))
label.textColor = UIColor.white
label.font = UIFont.boldSystemFont(ofSize: 14.0)
label.textAlignment = NSTextAlignment.center
label.text = "Please wait...."
myView.frame = CGRect(x: (UIScreen.main.bounds.size.width - 100)/2, y: (UIScreen.main.bounds.size.height - 100)/2, width: 100, height: 100)
myView.backgroundColor = UIColor.init(white: 0.0, alpha: 0.7)
myView.layer.cornerRadius = 5
activityIndicator.center = CGPoint(x: myView.frame.size.width/2, y: myView.frame.size.height/2 - 10)
myView.addSubview(activityIndicator)
myView.addSubview(label)
myView.isHidden = true
self.window?.addSubview(myView)
}
@IBAction func activityIndicatorStart(_ sender: Any) {
myView.isHidden = false
self.activityIndicator.startAnimating()
self.view.isUserInteractionEnabled = false
self.view.bringSubview(toFront: myView)
}
@IBAction func activityIndicatorStop(_ sender: Any)() {
myView.isHidden = true
self.activityIndicator.stopAnimating()
self.view.isUserInteractionEnabled = true
}
Ответ 7
Вы можете создать свой собственный индикатор активности с этим в Swift 3 и 4:
Создайте новый файл с именем: UIViewExtension.Swift, скопируйте этот код и вставьте в ваш новый файл:
import UIkit
extension UIView{
func customActivityIndicator(view: UIView, widthView: CGFloat? = nil,backgroundColor: UIColor? = nil, message: String? = nil,colorMessage:UIColor? = nil ) -> UIView{
//Config UIView
self.backgroundColor = backgroundColor ?? UIColor.clear
self.layer.cornerRadius = 10
var selfWidth = view.frame.width - 100
if widthView != nil{
selfWidth = widthView ?? selfWidth
}
let selfHeigh = CGFloat(100)
let selfFrameX = (view.frame.width / 2) - (selfWidth / 2)
let selfFrameY = (view.frame.height / 2) - (selfHeigh / 2)
let loopImages = UIImageView()
//ConfigCustomLoading with secuence images
let imageListArray = [UIImage(named:""),UIImage(named:""), UIImage(named:"")]
loopImages.animationImages = imageListArray
loopImages.animationDuration = TimeInterval(1.3)
loopImages.startAnimating()
let imageFrameX = (selfWidth / 2) - 17
let imageFrameY = (selfHeigh / 2) - 35
var imageWidth = CGFloat(35)
var imageHeight = CGFloat(35)
if widthView != nil{
imageWidth = widthView ?? imageWidth
imageHeight = widthView ?? imageHeight
}
//ConfigureLabel
let label = UILabel()
label.textAlignment = .center
label.textColor = .gray
label.font = UIFont.boldSystemFont(ofSize: 17)
label.numberOfLines = 0
label.text = message ?? ""
label.textColor = colorMessage ?? UIColor.clear
//Config frame of label
let labelFrameX = (selfWidth / 2) - 100
let labelFrameY = (selfHeigh / 2) - 10
let labelWidth = CGFloat(200)
let labelHeight = CGFloat(70)
//add loading and label to customView
self.addSubview(loopImages)
self.addSubview(label)
//Define frames
//UIViewFrame
self.frame = CGRect(x: selfFrameX, y: selfFrameY, width: selfWidth , height: selfHeigh)
//ImageFrame
loopImages.frame = CGRect(x: imageFrameX, y: imageFrameY, width: imageWidth, height: imageHeight)
//LabelFrame
label.frame = CGRect(x: labelFrameX, y: labelFrameY, width: labelWidth, height: labelHeight)
return self
}
}
И тогда вы можете использовать его в вашем ViewController следующим образом:
import UIKit
class ExampleViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(UIView().customActivityIndicator(view: self.view,backgroundColor: UIColor.green))
}
//function for stop and desappear loading
func deseappearLoading(){
self.view.subviews.last?.removeFromSuperview()
}
}
Не забудьте заменить [UIImage (named: ""), UIImage (named: ""), UIImage (named: "")] на ваши имена изображений и настроить TimeInterval (1.3). Наслаждайся этим.
Ответ 8
Я столкнулся с подобной проблемой в последнее время. И это мое решение. По сути, это то, что изначально хотел создатель темы: пустая страница с настраиваемым индикатором активности.
Я частично использовал ответ @Azharhussain Shaikh, но я реализовал автоматическую компоновку вместо использования фреймов и добавил несколько других уточнений, чтобы сделать использование как можно более простым.
Итак, это расширение для UIView с двумя методами: addActivityIndicator() и removeActivityIndicator()
extension UIView {
func addActivityIndicator() {
// creating a view (let call it "loading" view) which will be added on top of the view you want to have activity indicator on (parent view)
let view = UIView()
// setting up a background for a view so it would make content under it look like not active
view.backgroundColor = UIColor.white.withAlphaComponent(0.7)
// adding "loading" view to a parent view
// setting up auto-layout anchors so it would cover whole parent view
self.addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
view.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
view.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
view.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
view.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
// creating array with images, which will be animated
// in my case I have 30 images with names activity0.png ... activity29.png
var imagesArray = [UIImage(named: "activity\(0)")!]
for i in 1..<30 {
imagesArray.append(UIImage(named: "activity\(i)")!)
}
// creating UIImageView with array of images
// setting up animation duration and starting animation
let activityImage = UIImageView()
activityImage.animationImages = imagesArray
activityImage.animationDuration = TimeInterval(0.7)
activityImage.startAnimating()
// adding UIImageView on "loading" view
// setting up auto-layout anchors so it would be in center of "loading" view with 30x30 size
view.addSubview(activityImage)
activityImage.translatesAutoresizingMaskIntoConstraints = false
activityImage.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
activityImage.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
activityImage.widthAnchor.constraint(equalToConstant: 30).isActive = true
activityImage.heightAnchor.constraint(equalToConstant: 30).isActive = true
}
func removeActivityIndicator() {
// checking if a view has subviews on it
guard let lastSubView = self.subviews.last else { return }
// removing last subview with an assumption that last view is a "loading" view
lastSubView.removeFromSuperview()
} }
Эффект "вращения" достигается благодаря тем 30 изображениям, которые вы поместили в imagesArray. Каждое изображение - это новый кадр вращающегося индикатора, подобного этому.
Использование В вашем представлении контроллер для отображения индикатора активности просто вставьте:
view.addActivityIndicator()
Для удаления индикатора активности:
view.removeActivityIndicator()
Например, в случае использования этого с табличным представлением (как я делаю) это может использоваться следующим образом:
func setLoadingScreen() {
view.addActivityIndicator()
tableView.isScrollEnabled = false
}
func removeLoadingScreen() {
view.removeActivityIndicator()
tableView.isScrollEnabled = true
}
Работает в Swift 4.
Ответ 9
Swift 5
Другой ответ работает отлично
Шаг 1.
Создайте файл swift "CustomLoader.swift" и поместите этот код в этот файл
import UIKit
import CoreGraphics
import QuartzCore
class CustomLoader: UIView
{
//MARK:- NOT ACCESSABLE OUT SIDE
fileprivate var duration : CFTimeInterval! = 1
fileprivate var isAnimating :Bool = false
fileprivate var backgroundView : UIView!
//MARK:- ACCESS INSTANCE ONLY AND CHANGE ACCORDING TO YOUR NEEDS *******
let colors : [UIColor] = [.red, .blue, .orange, .purple]
var defaultColor : UIColor = UIColor.red
var isUsrInteractionEnable : Bool = false
var defaultbgColor: UIColor = UIColor.white
var loaderSize : CGFloat = 80.0
/// **************** ****************** ////////// **************
//MARK:- MAKE SHARED INSTANCE
private static var Instance : CustomLoader!
static let sharedInstance : CustomLoader = {
if Instance == nil
{
Instance = CustomLoader()
}
return Instance
}()
//MARK:- DESTROY TO SHARED INSTANCE
@objc fileprivate func destroyShardInstance()
{
CustomLoader.Instance = nil
}
//MARK:- SET YOUR LOADER INITIALIZER FRAME ELSE DEFAULT IS CENTER
func startAnimation()
{
let win = UIApplication.shared.keyWindow
backgroundView = UIView()
backgroundView.frame = (UIApplication.shared.keyWindow?.frame)!
backgroundView.backgroundColor = UIColor.init(white: 0, alpha: 0.4)
win?.addSubview(backgroundView)
self.frame = CGRect.init(x: ((UIScreen.main.bounds.width) - loaderSize)/2, y: ((UIScreen.main.bounds.height) - loaderSize)/2, width: loaderSize, height: loaderSize)
self.addCenterImage()
self.isHidden = false
self.backgroundView.addSubview(self)
self.layer.cornerRadius = loaderSize/2
self.layer.masksToBounds = true
backgroundView.accessibilityIdentifier = "CustomLoader"
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.NSExtensionHostDidBecomeActive, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(CustomLoader.ResumeLoader), name: NSNotification.Name.NSExtensionHostDidBecomeActive, object: nil)
self.layoutSubviews()
}
//MARK:- AVOID STUCKING LOADER WHEN CAME BACK FROM BACKGROUND
@objc fileprivate func ResumeLoader()
{
if isAnimating
{
self.stopAnimation()
self.AnimationStart()
}
}
override func layoutSubviews()
{
super.layoutSubviews()
self.backgroundColor = defaultbgColor
UIApplication.shared.keyWindow?.isUserInteractionEnabled = isUsrInteractionEnable
self.AnimationStart()
}
@objc fileprivate func addCenterImage()
{
/// add image in center
let centerImage = UIImage(named: "Logo")
let imageSize = loaderSize/2.5
let centerImgView = UIImageView(image: centerImage)
centerImgView.frame = CGRect(
x: (self.bounds.width - imageSize) / 2 ,
y: (self.bounds.height - imageSize) / 2,
width: imageSize,
height: imageSize
)
centerImgView.contentMode = .scaleAspectFit
centerImgView.layer.cornerRadius = imageSize/2
centerImgView.clipsToBounds = true
self.addSubview(centerImgView)
}
//MARK:- CALL IT TO START THE LOADER , AFTER INITIALIZE THE LOADER
@objc fileprivate func AnimationStart()
{
if isAnimating
{
return
}
let size = CGSize.init(width: loaderSize , height: loaderSize)
let dotNum: CGFloat = 10
let diameter: CGFloat = size.width / 5.5 //10
let dot = CALayer()
let frame = CGRect(
x: (layer.bounds.width - diameter) / 2 + diameter * 2,
y: (layer.bounds.height - diameter) / 2,
width: diameter/1.3,
height: diameter/1.3
)
dot.backgroundColor = colors[0].cgColor
dot.cornerRadius = frame.width / 2
dot.frame = frame
let replicatorLayer = CAReplicatorLayer()
replicatorLayer.frame = layer.bounds
replicatorLayer.instanceCount = Int(dotNum)
replicatorLayer.instanceDelay = 0.1
let angle = (2.0 * M_PI) / Double(replicatorLayer.instanceCount)
replicatorLayer.instanceTransform = CATransform3DMakeRotation(CGFloat(angle), 0.0, 0.0, 1.0)
layer.addSublayer(replicatorLayer)
replicatorLayer.addSublayer(dot)
let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
scaleAnimation.toValue = 0.4
scaleAnimation.duration = 0.5
scaleAnimation.autoreverses = true
scaleAnimation.repeatCount = .infinity
scaleAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
dot.add(scaleAnimation, forKey: "scaleAnimation")
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotationAnimation.toValue = -2.0 * Double.pi
rotationAnimation.duration = 6.0
rotationAnimation.repeatCount = .infinity
rotationAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
replicatorLayer.add(rotationAnimation, forKey: "rotationAnimation")
if colors.count > 1 {
var cgColors : [CGColor] = []
for color in colors {
cgColors.append(color.cgColor)
}
let colorAnimation = CAKeyframeAnimation(keyPath: "backgroundColor")
colorAnimation.values = cgColors
colorAnimation.duration = 2
colorAnimation.repeatCount = .infinity
colorAnimation.autoreverses = true
dot.add(colorAnimation, forKey: "colorAnimation")
}
self.isAnimating = true
self.isHidden = false
}
//MARK:- CALL IT TO STOP THE LOADER
func stopAnimation()
{
if !isAnimating
{
return
}
UIApplication.shared.keyWindow?.isUserInteractionEnabled = true
let winSubviews = UIApplication.shared.keyWindow?.subviews
if (winSubviews?.count)! > 0
{
for viw in winSubviews!
{
if viw.accessibilityIdentifier == "CustomLoader"
{
viw.removeFromSuperview()
// break
}
}
}
layer.sublayers = nil
isAnimating = false
self.isHidden = true
self.destroyShardInstance()
}
//MARK:- GETTING RANDOM COLOR , AND MANAGE YOUR OWN COLORS
@objc fileprivate func randomColor()->UIColor
{
let randomRed:CGFloat = CGFloat(drand48())
let randomGreen:CGFloat = CGFloat(drand48())
let randomBlue:CGFloat = CGFloat(drand48())
return UIColor(red: randomRed, green: randomGreen, blue: randomBlue, alpha: 1.0)
}
override func draw(_ rect: CGRect)
{
}
}
найдите имя функции и "addCenterImage" и замените имя изображения на свое собственное изображение.
Шаг 2
Создайте экземпляр класса AppDelegate вне класса AppDelegate следующим образом.
var AppInstance: AppDelegate!
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
{ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
{
AppInstance = self
}
Шаг 3.
поместите эти две функции в ваш AppDelegate
//MARK: - Activity Indicator -
func showLoader()
{
CustomLoader.sharedInstance.startAnimation()
}
func hideLoader()
{
CustomLoader.sharedInstance.stopAnimation()
}
Шаг 4. Используйте подобные функции всякий раз, когда вы хотите оживить загрузчик и остановиться.
AppInstance.showLoader()
AppInstance.hideLoader()
СЧАСТЛИВАЯ ЗАГРУЗКА...
Ответ 10
Версия Swift 5.0 принята Ответ
public extension UIImageView {
func spin(duration: Float) {
let rotation = CABasicAnimation(keyPath: "transform.rotation")
rotation.fromValue = 0
rotation.toValue = 2 * Double.pi
rotation.duration = 0.7
rotation.repeatCount = duration
layer.add(rotation, forKey: "spin")
}
func stopSpinning() {
layer.removeAllAnimations()
}
}