ios活动指标的A至Z指南

The idea of a standard interface with a bar along the top and the same menu choice across different applications dates back decades. Indeed, I can recall buying an Apple Macintosh and running the Paint app on it. The bar that it used (that was in 1984) looked almost identical to the bar that appears today. Yes, that’s almost 35 years, readers — incredible.

标准界面在顶部带有条形图,跨不同应用程序具有相同菜单选项的想法可以追溯到几十年前。 确实,我可以回想起购买Apple Macintosh并在其上运行Paint应用程序的情况。 它使用的条形图(在1984年)看起来与今天出现的条形图几乎相同。 是的,读者已经快35年了-太不可思议了。

It’s one of those ideas that was so good that it endures the test of time without missing a beat. Of course, today Apple publishes a monster volume of documentation on what has become known as human interface guidelines (HIG). Apple calls them guidelines, although in reality some are requirements — because Apple reserves the right to reject your app if you don’t follow them.

这是一个很棒的想法,它经受住了时间的考验而没有错过任何拍子。 当然,今天,苹果公司发布了大量关于所谓的人机界面指南(HIG)的文档 Apple称它们为准则,尽管实际上是一些要求-因为如果您不遵循它们,Apple保留拒绝您的应用程序的权利。

I want to focus on a practical aspect of those guidelines. An aspect that we’ve all used in our apps here and there is the activity indicator. Here’s a quick summary of what Apple’s HIG say about activity indicators:

我想专注于这些准则的实践方面。 我们在这里的应用程序中都使用过的一个方面是活动指示器。 这是Apple HIG关于活动指标的简要说明:

  • Make it clear when something is loading (aka use an activity indicator)

    清楚说明什么时候正在加载(也可以使用活动指示器)
  • Show content as soon as possible (make sure you use a GCD utility/background thread to actually load your data)

    尽快显示内容(确保使用GCD实用程序/后台线程实际加载数据)
  • Educate and entertain users on why you do it (eye candy is good)

    对用户进行教育和娱乐,说明您这样做的原因(好吃的糖果)
  • Don’t use the standard indicators if you have time to do something better

    如果您有时间做得更好,请不要使用标准指标

This is all excellent advice, although the last point needs a tad more explanation. What Apple’s saying here, I think, is that whatever solution you put in place, keep it inn context. So if it takes two seconds to load, it’s OK to use an Apple indicator. But if it takes 10 seconds to load, then you better come up with something better … or else.

尽管最后一点需要更多解释,但这都是非常好的建议。 我认为,苹果在这里所说的是,无论您采用什么解决方案,都应将其保持在旅馆环境中。 因此,如果加载需要两秒钟,则可以使用Apple指示器。 但是,如果加载需要10秒钟,那么您最好提出更好的方法…否则。

OK, to the code: Let’s use a UIKit ActivityIndicator in our SwiftUI 1.0 (Xcode 11.7) project. A very basic, boring one — just to start off gently.

OK,输入代码:让我们在SwiftUI 1.0(Xcode 11.7)项目中使用UIKit ActivityIndicator 。 一个非常基本的,无聊的-只是轻轻地开始。

struct ContentView: View {
    @State var isLoading = true
    var body: some View {
        VStack {
            ActivityIndicator(isAnimating: isLoading)
              .configure { $0.color = .red
                           $0.style = .large
                           $0.hidesWhenStopped = true
              }
              .padding()
              .background(Color.clear)
              
        }.onTapGesture {
            self.isLoading.toggle()
        }
    }
}


struct ActivityIndicator: UIViewRepresentable {
    
    typealias UIView = UIActivityIndicatorView
    var isAnimating: Bool
    fileprivate var configuration = { (indicator: UIView) in }


    func makeUIView(context: UIViewRepresentableContext<Self>) -> UIView { UIView() }
    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<Self>) {
        isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
        configuration(uiView)
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


extension View where Self == ActivityIndicator {
    func configure(_ configuration: @escaping (Self.UIView)->Void) -> Self {
        Self.init(isAnimating: self.isAnimating, configuration: configuration)
    }
}
Image for post
Standard iOS activity indicator, with basic customisation
标准iOS活动指示器,具有基本自定义功能

This is good — but wait — delving deeper into the Apple documentation, they say you should favour progress bars over activity indicators. You should, at the very least, give the user an indication of how long they have to wait. Let’s do one of those, too.

很好-但是请稍等-深入研究Apple文档,他们说您应该比活动指示器更喜欢进度条。 您至少应该给用户一个指示,他们必须等待多长时间。 让我们也做其中之一。

struct ContentView: View {
    @State private var downloadAmount = 0.0
    let timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()
    
    var body: some View {
      ProgressView_iOS13(percentage: Float(downloadAmount))
        .onReceive(timer) { _ in
            if downloadAmount < 100 {
                downloadAmount += 2
            }
        }
    }
}


struct ProgressView_iOS13: UIViewRepresentable {
  
  typealias UIView = UIProgressView
  var percentage: Float
  fileprivate var configuration = { (indicator: UIView ) in }
  
  func makeUIView(context: UIViewRepresentableContext<Self>) -> UIView { UIView() }
  func updateUIView(_ uiView: UIViewType, context: UIViewRepresentableContext<Self>) {
    uiView.setProgress(percentage, animated: true)
    configuration(uiView)
  }
}

This code will produce a bar that fills up, just like this:

此代码将产生一个填充的条,如下所示:

Image for post
Basic progress bar in iOS
iOS中的基本进度栏

Super, we’re on a roll. But hold on — stop the press — news just in! iOS 14 has native support for the progress bars. That looks like this:

超级,我们进展顺利。 但是,请稍等-停止新闻发布-新闻刚刚出现! iOS 14对进度条具有本机支持。 看起来像这样:

struct ProgressIndicator_iOS14: View {
    @State private var downloadAmount = 0.0
    let timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()
    var body: some View {
        VStack {
            ProgressView("Downloading…", value: downloadAmount, total: 100)
        }
        .onReceive(timer) { _ in
            if downloadAmount < 100 {
                downloadAmount += 2
            }
        }
    }
}

It looks identical, obviously, to the iOS13 version, so I’ll spare you the animated GIF this time.

显然,它看起来与iOS13版本相同,所以这次我将为您保留动画GIF。

At this point, we’ve done all the template code. Now what about point #4? My load takes more than 10 seconds. What about some custom activity/percentage indicators? Let’s try and code some of those.

至此,我们已经完成了所有模板代码。 现在第四点呢? 我的负载需要10秒钟以上。 某些自定义活动/百分比指标呢? 让我们尝试对其中一些进行编码。

We have two types: an indeterminate type that you use for delays of an unknown length and a determinate type for when you know how much is loading. Using a circle can work well for either, just like the standard Apple indicators — but hopefully with a bit more finesse.

我们有两种类型:一种用于不确定长度的延迟的不确定类型一种用于在知道加载量时的不确定类型。 就像标准的Apple指示器一样,​​使用圆圈可以很好地适用于任何一个,但希望可以有更多的技巧。

Here’s the basic code for a custom determinate loading indicator.

这是自定义确定加载指示器的基本代码。

struct Fonts {
  static func avenirNextCondensedMedium (size: CGFloat) -> Font {
    return Font.custom("AvenirNextCondensed-Medium", size: size)
  }
}


struct ContentView: View {
    @State private var downloadAmount: Double = 0
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    
    var body: some View {
      CustomIndicator2(downloadAmount: $downloadAmount)
        .onReceive(timer) { _ in
            if downloadAmount < 299
            {
                downloadAmount += 60
            } else {
               downloadAmount = 0
            }
        }
    }
}


struct CustomIndicator2: View {
  @Binding var downloadAmount: Double
  @State var fadeIn:Double = 0
  var body: some View {
    ZStack {
      PieArc(pieSlice: downloadAmount)
        .fill(Color.green)
        .rotationEffect(.degrees(-90))
        .frame(width: 128, height: 128)
        .onChange(of: downloadAmount) { (_) in
          print("pieSlice ",downloadAmount)
        }
      Circle()
        .fill(Color.white)
        .frame(width: 96, height: 96)
      Circle()
        .stroke(Color.black, lineWidth: 2)
        .frame(width: 90, height: 90)
      Circle()
        .stroke(Color.black, lineWidth: 2)
        .frame(width: 128, height: 128)
      Text(String(Int((((downloadAmount + 60) / 360)) * 100)) + "%")
        .font(Fonts.avenirNextCondensedMedium(size: 24))
        .foregroundColor(Color.black)
    }
  }
}


struct PieArc: Shape {
    @State var pieSlice:Double
    func path(in rect: CGRect) -> Path {
      var piePath = Path()
      piePath.addArc(center: CGPoint(x: rect.width/2, y:rect.height/2), radius: 64, startAngle: .degrees(0), endAngle: .degrees(pieSlice+60), clockwise: false)
      piePath.addLine(to: CGPoint(x: rect.width/2, y:rect.height/2))
      piePath.closeSubpath()
      return piePath
    }
}

When this code is running, it looks like this:

该代码运行时,如下所示:

Image for post

Now, to make this an indeterminate type, you need to change just one parameter on this line and, of course, remove the text label.

现在,要使其成为不确定的类型,您只需要在此行上更改一个参数,然后删除文本标签即可。

piePath.addArc(center: CGPoint(x: rect.width/2, y:rect.height/2), radius: 64, startAngle: .degrees(0), endAngle: .degrees(pieSlice+60), clockwise: false)

These changes will turn get your indicator looking like this. Obviously, you’d want to make this run a bit faster and make it look a little more snappy.

这些变化将使您的指标看起来像这样。 显然,您希望使此过程运行得更快一些,并使它看起来更灵活一些。

Image for post

Just before I go, however, let’s do just one more. Let’s do an indicator that uses an image and some shapes. This is eye candy.

但是,在我走之前,我们再做一个。 让我们做一个使用图像和一些形状的指标。 这是眼睛糖果。

struct ContentView: View {
    @State private var downloadAmount: Double = 0
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    
    var body: some View {
        CustomIndicator3(downloadAmount: $downloadAmount)
        .onReceive(timer) { _ in
            if downloadAmount < 20 {
               downloadAmount += 1
            }
        }
    }
}




struct CustomIndicator3: View {
  @Binding var downloadAmount: Double
  @State var boxes = [Double](repeating: 0.0, count: 20)
   var body: some View {
    ZStack {
      Rectangle()
        .fill(LinearGradient(gradient: Gradient(colors: [.white, .purple, .blue, .black]), startPoint: .top, endPoint: .bottom))
        .frame(width: 442, height: 300)
      Circle()
        .fill(Color.white)
        .frame(width: 48, height: 48)
        .offset(x: 24, y: CGFloat(downloadAmount * -10) + 80)
      Circle()
        .stroke(Color.black, lineWidth: 1)
        .frame(width: 48, height: 48)
        .offset(x: 24, y: CGFloat(downloadAmount * -10) + 80)
      Image("NYC-skyline_no-background")
        .resizable()
        .frame(width: 342, height: 342)
      HStack(spacing: 2) {
        ForEach(0 ..< 20) {loop in
          RoundedRectangle(cornerRadius: 4)
            .fill(Color.white)
            .frame(width: 12, height: 16)
            .offset(x: CGFloat(Double(loop) * 1.2), y: 135)
            .opacity(boxes[loop])
            .onChange(of: downloadAmount) { (_) in
              for i in 0..<Int(downloadAmount) {
                boxes[i] = 1.0
              }
            }
        }
      }
    }
   }
}

It’s a cartoon image of New York drawn by Mark Higden. I’ve added a background and an animated moon — as well as a loading bar at the bottom to show you the progress.

这是马克·希格登(Mark Higden)绘制的纽约卡通形象。 我添加了背景和动画的月亮-并在底部添加了一个加载栏,以向您显示进度。

Image for post
markhigden.com markhigden.com

This brings me to the end of this article. I hope you enjoyed reading it as much as I did writing it.

这使我到本文的结尾。 我希望您和我一样喜欢阅读它。

Keep calm, and keep coding.

保持冷静,并保持编码。

翻译自: https://medium.com/better-programming/an-a-to-z-guide-to-ios-activity-indicators-43c8a3da39c2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值