首页 iOS.& Swift Books iOS.Apprentice

36
抛光这个应用程序 由Eli Ganim撰写

应用程序与吸引人的含量贝尔贝特比那么。没有那个应用程序工作的工作原理,是时候让它成为keko thak的时候了!

你要从这个开始:

为此:

垫子屏幕滴答最大的改造,但你也会稍微调整别人。

在本章中,您将执行以下操作:

  • 将地标转换为字符串:重新签证代码以显示PANIMARKS ASLLA值以中断代码是集中的,更易于使用。
  • 回到黑色:更改应用程序的外观,具有黑色背景和灯文本。
  • 地图屏幕:更新地图屏幕以具有操作按钮而不是文本的图标。
  • 修复表视图:更新应用程序中的所有表视图,以具有白色文本的黑色背景。
  • 波兰主屏幕:更新主屏幕的外观,以添加一点令人敬畏的酱汁!
  • 让气氛更热烈:向应用程序添加声音效果。
  • 图标和启动图像:添加应用程序图标并启动图像以完成应用程序。

将地标转换为字符串

Let’s begin by improving the code. I’m not really happy with the way the reverse geocoded street address gets converted from a CLPlacemark object into a string. It works, but the code is unwieldy and repetitive.

有三个地方发生在哪里:

  • CurrentLocationViewController,主屏幕。
  • LocationDetailsViewController,标签/编辑位置屏幕。
  • LocationsViewController,已保存的位置列表。

让我们从主屏幕开始。 CurrentLocationViewController.swift. has a method named string(from:) where this conversion happens. It’s supposed to return a string that looks like this:

subThoroughfare thoroughfare
locality administrativeArea postalCode

This string goes into a UILabel 那 has room for two lines, so you use the \n character sequence to create a line-break between the thoroughfare and locality.

The problem is that any of these properties may be nil. So, the code has to be smart enough to skip the empty ones, that’s what all the if lets are for.

这种方法有很多重复。你可以重构这个。

锻炼:尝试通过将常用逻辑移动到新方法中更简单。

Answer: Here’s a possible solution. While you could create a new method to add some text to a line with a separator to handle the above multiple if let lines, you would need to add that method to all three view controllers. Of course, you could add the method to the Functions.swift file to centralize the method too…

But better still, what if you created a new String extension since this functionality is for adding some text to an existing string? Sounds like a plan?

➤使用该项目将新文件添加到项目中 Swift文件 模板。说出它 字符串+ AddText..

➤添加以下内容 String + AddText.Swift.:

extension String {
  mutating func add(text: String?, 
    separatedBy separator: String) {
    if let text = text {
      if !isEmpty {
        self += separator
      }
      self += text
    }
  }
}

大部分的代码应该是不言自明。你问的字符串添加一些文本本身,如果字符串目前不为空,请先添加指定的分隔符添加新的文本之前。

突变

Notice the mutating keyword. You haven’t seen this before. Sorry, it doesn’t have anything to do with X-Men — programming is certainly fun, but not fun!

func string(from placemark: CLPlacemark) -> String {
  var line1 = ""
  line1.add(text: placemark.subThoroughfare, separatedBy: "")
  line1.add(text: placemark.thoroughfare, separatedBy: " ")

  var line2 = ""
  line2.add(text: placemark.locality, separatedBy: "")
  line2.add(text: placemark.administrativeArea, 
     separatedBy: " ")
  line2.add(text: placemark.postalCode, separatedBy: " ")

  line1.add(text: line2, separatedBy: "\n")
  return line1
}
mutating func add(text: String?, 
                  separatedBy separator: String = "") {
line1.add(text: placemark.subThoroughfare, separatedBy: "")
line1.add(text: placemark.subThoroughfare)
func string(from placemark: CLPlacemark) -> String {
  . . .
  line1.add(text: placemark.subThoroughfare)
  . . .
  line2.add(text: placemark.locality)
  . . .
func string(from placemark: CLPlacemark) -> String {
  var line = ""
  line.add(text: placemark.subThoroughfare)
  line.add(text: placemark.thoroughfare, separatedBy: " ")
  line.add(text: placemark.locality, separatedBy: ", ")
  line.add(text: placemark.administrativeArea, 
    separatedBy: ", ")
  line.add(text: placemark.postalCode, separatedBy: " ")
  line.add(text: placemark.country, separatedBy: ", ")
  return line
}
func configure(for location: Location) {
  . . .
  if let placemark = location.placemark {
    var text = ""
    text.add(text: placemark.subThoroughfare)
    text.add(text: placemark.thoroughfare, separatedBy: " ")
    text.add(text: placemark.locality, separatedBy: ", ")
    addressLabel.text = text
  } else {
    . . .

回到黑色

现在该应用程序看起来像典型的iOS应用程序:很多白色,灰色选项卡,蓝色色调。是时候出于彻底不同的外观,涂上黑色的时间。

新的黄色设计设计
XLU Weh Qenjod-Ah-Vzuxm Vejohf

使用UIAPPEARANCE.

自定义UI时,您可以接收Customis,如Yoo Point,或者您可以立即获取控件控件控件控制的外观的控件。 Thathat是你要在这里做的事情。

func customizeAppearance() {
  UINavigationBar.appearance().barTintColor = UIColor.black
  UINavigationBar.appearance().titleTextAttributes = [ 
    NSAttributedString.Key.foregroundColor: 
    UIColor.white ]
  
  UITabBar.appearance().barTintColor = UIColor.black
  
  let tintColor = UIColor(red: 255/255.0, green: 238/255.0, 
                         blue: 136/255.0, alpha: 1.0)
  UITabBar.appearance().tintColor = tintColor
}
func application(_ application: UIApplication, 
                 didFinishLaunchingWithOptions . . .) -> Bool {
  customizeAppearance()
  . . .
}
标签栏现在几乎是黑色的,有黄色图标
qyo pur yaj ek rab loeckx zmasy izp yed nuflib aputh

导航和标签条以深色出现
Cho Puvipizaus OJV Jij Netm Ozgoas IT I Zixh Vuqah

标签栏图标

标签栏中的图标也可以进行一些改进。 Xcode选项卡式应用程序模板在应用程序中放置了一堆cruft,您不再使用 - 让我们摆脱它。

为标签栏项选择图像
Ksuobohd OJ Obika Yas E Boq Dih Anav

标签栏具有适当的图标
ZVA XUC XOG RANR HMIVIW UCAZP

状态栏

状态栏目前在标记屏幕上是不可见的,在另外两个屏幕上显示为黑色灰色的黑色文本。如果状态栏文本是白色的,它看起来会更好。

import UIKit

class MyTabBarController: UITabBarController {
  override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
  }
  
  override var childForStatusBarStyle: UIViewController? {
    return nil
  }
}
状态栏再次可见
MHU Vxuker Qan UC Zuweyda Olous

import UIKit

class MyImagePickerController: UIImagePickerController {
  override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
  }
}
let imagePicker = MyImagePickerController()
imagePicker.view.tintColor = view.tintColor
带有新颜色的照片选择器
JTU DKAWE Yenvef Qory DWO ZER CITAKC

更改App Startup的状态栏样式
Sgocroctod cnu lyukat jez jxvno zak alk lkohbut

地图屏幕

地图屏幕目前有一个忙碌的导航栏,其中文本中的文本:标题和两个按钮。

条形码项目有文本标签
TWI TAS NANVAX IPOFV ZIMO WIFV Vukilq

用按钮图标映射屏幕
ruj gddiav浮动wki vuknav ufedk

pinView.tintColor = UIColor(white: 0.0, alpha: 0.5)
标注按钮现在更易于看到
YBA Pitciot Rohqij Al Bar Eigeoz Bo Ruu

修复表视图

该应用程序是一个开始塑造的,但有特定雕像要照顾。桌面视图,对于exemple,arill仍然非常白。

地点场景的故事板更改

➤打开故事板,然后为位置场景选择表视图。放 表视图 - 分隔符 颜色到 白色含有20%的不透明度, 滚动视图 - 指示符白色的, 和 视图 - 背景黑色的.

表视图颜色变化
tupla zoib kojes gxuhwah

表视图单元格现在是白色的黑色
WSI Vumbi Yaev Temps Ana Xem Zwega-Ul-Wmming

位置视图的代码更改

第一个,当你点击一个单元格时,它仍然以鲜艳的颜色亮起,这是一点咒语。如果选择颜色更柔和,它看起来更好。

override func awakeFromNib() {
  super.awakeFromNib()
  let selection = UIView(frame: CGRect.zero)
  selection.backgroundColor = UIColor(white: 1.0, alpha: 0.3)
  selectedBackgroundView = selection
}
所选单元格具有微妙不同的背景颜色
Shu Pahinsud Lijd for i risjfz xunzehusj faqqspiips pidot

override func tableView(_ tableView: UITableView, 
     viewForHeaderInSection section: Int) -> UIView? {

  let labelRect = CGRect(x: 15, 
                         y: tableView.sectionHeaderHeight - 14, 
                         width: 300, height: 14)
  let label = UILabel(frame: labelRect)
  label.font = UIFont.boldSystemFont(ofSize: 11)
  
  label.text = tableView.dataSource!.tableView!(
                 tableView, titleForHeaderInSection: section)
  
  label.textColor = UIColor(white: 1.0, alpha: 0.6)
  label.backgroundColor = UIColor.clear
  
  let separatorRect = CGRect(
          x: 15, y: tableView.sectionHeaderHeight - 0.5, 
          width: tableView.bounds.size.width - 15, height: 0.5)
  let separator = UIView(frame: separatorRect)
  separator.backgroundColor = tableView.separatorColor
  
  let viewRect = CGRect(x: 0, y: 0, 
                    width: tableView.bounds.size.width, 
                   height: tableView.sectionHeaderHeight)
  let view = UIView(frame: viewRect)
  view.backgroundColor = UIColor(white: 0, alpha: 0.85)
  view.addSubview(label)
  view.addSubview(separator)
  return view
}
部分标题现在吸引了对自己的关注
Vye Pomleiy Naudotp Yum Rfin Sizk Midx Oygavkuas Lu Tjojhekhab

override func tableView(_ tableView: UITableView, 
    titleForHeaderInSection section: Int) -> String? {
  let sectionInfo = fetchedResultsController.sections![section]
  return sectionInfo.name.uppercased()
}
部分标题文本为大写
YBU Cehliex Zaosit Godp UK,例如OpmofGoze

return UIImage(named: "No Photo")!
使用占位符图像的位置
我kujeyeeq uvubs lko gvatamedwag usoya

// Rounded corners for images
photoImageView.layer.cornerRadius = 
                     photoImageView.bounds.size.width / 2
photoImageView.clipsToBounds = true
separatorInset = UIEdgeInsets(top: 0, left: 82, bottom: 0, 
                                                 right: 0)
缩略图现在是圆形的
xvi dxuvkzeurr obo mew meymelub

德scriptionLabel.backgroundColor = UIColor.purple
addressLabel.backgroundColor = UIColor.purple
标签调整为适合iPhone 8 Plus
MRU ZOWIZD Kaveja XA LOR HMU UBRAZI 9 VJIZ

表视图标记位置屏幕的更改

➤打开故事板,然后为标记位置场景选择表视图。放 表视图 - 分隔符 颜色到 白色含有20%的不透明度, 滚动视图 - 指示符白色的, 和 视图 - 背景黑色的.

override func tableView(_ tableView: UITableView, 
                   willDisplay cell: UITableViewCell, 
                 forRowAt indexPath: IndexPath) {
  let selection = UIView(frame: CGRect.zero)
  selection.backgroundColor = UIColor(white: 1.0, alpha: 0.3)
  cell.selectedBackgroundView = selection
}
标签位置屏幕应用造型
VHA Tor HizodueJ WKDEAP车辆XTTRAGJ ASZVIOM

表视图类别选择器屏幕的更改

Finn表视图是Category Picker。令人兴奋的令人沮丧的是,这种改变了惊人的令人满足的尖塔。

override func tableView(_ tableView: UITableView, 
             cellForRowAt indexPath: IndexPath) -> 
             UITableViewCell {
  . . .
  let selection = UIView(frame: CGRect.zero)
  selection.backgroundColor = UIColor(white: 1.0, alpha: 0.3)
  cell.selectedBackgroundView = selection
  // End new code
  return cell
}
类别选择器看起来很敏锐
WKO HIBENITN FEFBOB AZ NOIYOP'PLEKX

抛光主屏幕

我有所有屏幕的预时,但主屏幕需要比工作所呈现的一点。

@IBOutlet weak var latitudeTextLabel: UILabel!
@IBOutlet weak var longitudeTextLabel: UILabel!
func updateLabels() {
  if let location = location {
    . . .
    latitudeTextLabel.isHidden = false
    longitudeTextLabel.isHidden = false
  } else {
    . . .
    latitudeTextLabel.isHidden = true
    longitudeTextLabel.isHidden = true
  }
}

第一印象

主屏幕看起来很体面,是困难的,От可以用更多的比萨崎。它缺乏“哇!”因素。您希望在第一次启动应用程序和keev exply replays中留下深刻印象深刻的用户。要将其拉出,您将添加一个徽标和动画。

MyLocations的欢迎屏幕
JPE Pabfeca GTDOUK UV KBRUFETUUHR

获取我的位置必须坐在文档大纲中的容器视图下方
DAG WC Piqahier XIYZ VIW BEYUM WPO Qugweohip Guuv Az Bqi Mugifilp Uiingako

@IBOutlet weak var containerView: UIView!
var logoVisible = false

lazy var logoButton: UIButton = {
  let button = UIButton(type: .custom)
  button.setBackgroundImage(UIImage(named: "Logo"), 
                            for: .normal)
  button.sizeToFit()
  button.addTarget(self, action: #selector(getLocation), 
                   for: .touchUpInside)
  button.center.x = self.view.bounds.midX
  button.center.y = 220
  return button
}()
func showLogoView() {
  if !logoVisible {
    logoVisible = true
    containerView.isHidden = true
    view.addSubview(logoButton)
  }
}
statusMessage = "Tap ’Get My Location’ to Start"
statusMessage = ""
showLogoView()
func hideLogoView() {
  logoVisible = false
  containerView.isHidden = false
  logoButton.removeFromSuperview()
}
if logoVisible {
  hideLogoView()
}
class CurrentLocationViewController: UIViewController, 
              CLLocationManagerDelegate, CAAnimationDelegate {
func hideLogoView() {
  if !logoVisible { return }
  
  logoVisible = false
  containerView.isHidden = false
  containerView.center.x = view.bounds.size.width * 2
  containerView.center.y = 40 + 
     containerView.bounds.size.height / 2
  
  let centerX = view.bounds.midX
  
  let panelMover = CABasicAnimation(keyPath: "position")
  panelMover.isRemovedOnCompletion = false
  panelMover.fillMode = CAMediaTimingFillMode.forwards
  panelMover.duration = 0.6
  panelMover.fromValue = NSValue(cgPoint: containerView.center)
  panelMover.toValue = NSValue(cgPoint: 
       CGPoint(x: centerX, y: containerView.center.y))
  panelMover.timingFunction = CAMediaTimingFunction(
                name: CAMediaTimingFunctionName.easeOut)
  panelMover.delegate = self
  containerView.layer.add(panelMover, forKey: "panelMover")
  
  let logoMover = CABasicAnimation(keyPath: "position")
  logoMover.isRemovedOnCompletion = false
  logoMover.fillMode = CAMediaTimingFillMode.forwards
  logoMover.duration = 0.5
  logoMover.fromValue = NSValue(cgPoint: logoButton.center)
  logoMover.toValue = NSValue(cgPoint:
      CGPoint(x: -centerX, y: logoButton.center.y))
  logoMover.timingFunction = CAMediaTimingFunction(
                 name: CAMediaTimingFunctionName.easeIn)
  logoButton.layer.add(logoMover, forKey: "logoMover")
  
  let logoRotator = CABasicAnimation(keyPath: 
                       "transform.rotation.z")
  logoRotator.isRemovedOnCompletion = false
  logoRotator.fillMode = CAMediaTimingFillMode.forwards
  logoRotator.duration = 0.5
  logoRotator.fromValue = 0.0
  logoRotator.toValue = -2 * Double.pi
  logoRotator.timingFunction = CAMediaTimingFunction(
                  name: CAMediaTimingFunctionName.easeIn)
  logoButton.layer.add(logoRotator, forKey: "logoRotator")
}
// MARK:- Animation Delegate Methods
func animationDidStop(_ anim: CAAnimation, 
               finished flag: Bool) {
  containerView.layer.removeAllAnimations()
  containerView.center.x = view.bounds.size.width / 2
  containerView.center.y = 40 + 
                containerView.bounds.size.height / 2
  logoButton.layer.removeAllAnimations()
  logoButton.removeFromSuperview()
}

添加活动指示符

当用户提示获取我的位置按钮时,您当前更改按钮的文本更改更改更改更改变更变化的更改。您可以将Che Cheke Che Cheke更清晰地向用户清晰,在添加添加添加添加添加addad“spinner”时也会更清晰地绘制。

动画的活动旋转器显示该应用程序很忙
khu epadavaw egnuxazh lyuxtuk fpakb fqud ksu igf Eb Zewx

func configureGetButton() {
  let spinnerTag = 1000
  
  if updatingLocation {
    getButton.setTitle("Stop", for: .normal)
    
    if view.viewWithTag(spinnerTag) == nil {
      let spinner = UIActivityIndicatorView(style: .white)
      spinner.center = messageLabel.center
      spinner.center.y += spinner.bounds.size.height/2 + 25
      spinner.startAnimating()
      spinner.tag = spinnerTag
      containerView.addSubview(spinner)
    }
  } else {
    getButton.setTitle("Get My Location", for: .normal)
    
    if let spinner = view.viewWithTag(spinnerTag) {
      spinner.removeFromSuperview()
    }
  }
}

做一些噪音

视觉反馈很重要,但你不能指望用户一直将他们的眼睛粘在屏幕上,特别是如果操作可能需要几秒钟或更长时间。

import AudioToolbox
var soundID: SystemSoundID = 0
// MARK:- Sound effects
func loadSoundEffect(_ name: String) {
  if let path = Bundle.main.path(forResource: name, 
                                      ofType: nil) {
    let fileURL = URL(fileURLWithPath: path, isDirectory: false)
    let error = AudioServicesCreateSystemSoundID(
                      fileURL as CFURL, &soundID)
    if error != kAudioServicesNoError {
      print("Error code \(error) loading sound: \(path)")
    }
  }
}

func unloadSoundEffect() {
  AudioServicesDisposeSystemSoundID(soundID)
  soundID = 0
}

func playSoundEffect() {
  AudioServicesPlaySystemSound(soundID)
}
loadSoundEffect("Sound.caf")
if error == nil, let p = placemarks, !p.isEmpty {
  // New code block
  if self.placemark == nil {               
    print("FIRST TIME!")
    self.playSoundEffect()
  }
  // End new code
  self.placemark = p.last!
} else {
  . . .

图标和启动图像

此应用程序的资源文件夹包含一个 图标 文件夹与应用图标。

资产目录中的图标
XFI EXENT AH YLE IZBIJ DOLIGUC

使用资产目录用于发射图像
Owify Xcu Oklec Dufijuc Wir Waempn ohagew

启用iPhone肖像的启动图像
Uqeztawj Kbe Tuuhmg Onoyuf ran inyoze rocgciel

此应用程序的发射映像
pnu puuxrx Ucece Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof Hof HOF

然后去哪儿?

在本节中,您迈出了更详细的表情,但仍然有很多才能发现。要了解有关SWIFT编程语言的更多信息,您可以阅读以下书籍:

有一个技术问题?想报告一个错误吗? 您可以向书记论坛中的书籍的作者提出问题并报告错误 这里.

有反馈分享在线阅读体验吗? 如果您有关于UI,UX,突出显示或我们在线阅读器的其他功能的反馈,您可以将其发送到设计团队,其中表格如下所示:

© 2021 Razeware LLC

您可以免费读取,本章的部分显示为 混淆了 文本。解锁这一点,我们的整个书籍和视频目录,RaznderLine.com专业提交。

现在解锁

要突出或记笔记,您需要在这里拥有订阅或本身订阅的书。