IOS自学记录P1

project1(GoodAsOldPhones)

基于上次的思维导图,准备一个一个项目的记录,先上第一个项目的截图
在这里插入图片描述

这是xcode中Main.storybard的截图
这是xcode中main.storyboard的截图
图片中有一个tab bar controller, 一个navigation controller,这两个在Editor菜单中的Embed in都能找到,tab bar controller 目的就是在屏幕下方生成tab bar,navigation controller的目的就是屏幕上方生成navigation bar,还有一个用于显示"老电话列表"的view controller,可以看见上面有一个table view,和一个显示老电话详情的view controller,另外一个tab bar用于显示us的内容,一共五个页面

先看ProductsTableViewController的代码

import UIKit

class ProductsTableViewController: UITableViewController {
  fileprivate var products: [Product]?
  fileprivate let identifer = "productCell"
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    products = [
      Product(name: "1907 Wall Set", cellImageName: "image-cell1", fullscreenImageName: "phone-fullscreen1"),
      Product(name: "1921 Dial Phone", cellImageName: "image-cell2", fullscreenImageName: "phone-fullscreen2"),
      Product(name: "1937 Desk Set", cellImageName: "image-cell3", fullscreenImageName: "phone-fullscreen3"),
      Product(name: "1984 Moto Portable", cellImageName: "image-cell4", fullscreenImageName: "phone-fullscreen4")
    ]
  }
  
  // MARK: - UITableViewDataSource
  override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return products?.count ?? 0
  }
  
  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: identifer, for: indexPath)
    guard let products = products else { return cell }
    
    cell.textLabel?.text = products[(indexPath as NSIndexPath).row].name
    
    if let imageName = products[(indexPath as NSIndexPath).row].cellImageName {
      cell.imageView?.image = UIImage(named: imageName)
    }
    
    return cell;
  }
  
  // MARK: - View Transfer
  override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showProduct" {
      if let cell = sender as? UITableViewCell,
        let indexPath = tableView.indexPath(for: cell),
        let productVC = segue.destination as? ProductViewController {
        productVC.product = products?[(indexPath as NSIndexPath).row]
      }
    }
  }
}

该controller继承UITableViewController
需要实现两个方法
1、numberOfRowsInSection
2、cellForRowAt

numberOfRowsInSection

返回的是一个section中有多少row,是一个int类型

cellForRowAt

这个方法返回一个UITableViewCell的实例

首先要讲的是 tableView.dequeueReusableCell(withIdentifier: identifer, for: indexPath) 这个方法,这个是为了效率,重复利用UITableViewCell,这个identifer在Main.storyboard可以设置
在这里插入图片描述

guard let products = products else { return cell }

Swift规定,guard - else必须同时出现,而且,else中,必须进行return。
这是一个比较常见的swift的用法,意思是除非products有值,否则return cell,有值之后会继续执行下面的代码,接下的两个方法其实是设置cell的textLabel和imageView

prepare方法

这个方法其实和tableview没啥关系,只是用于转场(segue) 的方法,定义转场是在Main.storyboard里设置的,按住ctrl,鼠标左键点击tableViewCell然后拖拉到productViewController上,选择类型为push,然后输入identifier,如下图
在这里插入图片描述

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showProduct" {
      if let cell = sender as? UITableViewCell,
        let indexPath = tableView.indexPath(for: cell),
        let productVC = segue.destination as? ProductViewController {
        productVC.product = products?[(indexPath as NSIndexPath).row]
      }
    }
  }

sender如果转型成UITableViewCell成功,则tableView.indexPath可以根据传入的cell获得相应的indexPath,为啥要获得indexPath呢?因为segue.destination as? ProductViewController这个含义是转场的目的地如果是ProductViewController
的话,则把products数组中下标为indexPath(前面得到的)的赋值给ProductViewController实例的product这个属性

ProductViewController 代码

import UIKit

class ProductViewController: UIViewController {

  @IBOutlet var productImageView: UIImageView!
  @IBOutlet var productNameLabel: UILabel!
  
  var product: Product?

  override func viewDidLoad() {
    super.viewDidLoad()
    
    productNameLabel.text = product?.name
    
    if let imageName = product?.fullscreenImageName {
      productImageView.image = UIImage(named: imageName)
    }
  }

  @IBAction func addToCartButtonDidTap(_ sender: AnyObject) {
    print("Add to cart successfully")
  }
}

这个controller没啥好讲的,类属性product就是接受上个controller的传入的值
UIImage(named: imageName)这个方法可以直接获得image

ContactViewController

import UIKit

class ContactViewController: UIViewController {
  
  @IBOutlet weak var scrollView: UIScrollView!
  
  override func viewDidLoad() {
    super.viewDidLoad()

    view.addSubview(scrollView)
  }
  
  override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if #available(iOS 11.0, *) {
      scrollView.frame = CGRect(x: 0, y: view.safeAreaInsets.top, width: view.frame.width, height: view.frame.height - view.safeAreaInsets.bottom - view.safeAreaInsets.top)
      
    } else {
      scrollView.frame = CGRect(x: 0, y: topLayoutGuide.length, width: view.frame.width, height: view.frame.height - topLayoutGuide.length - bottomLayoutGuide.length)
    }

    scrollView.contentSize = CGSize(width: self.view.frame.width, height: 800)
    print(self.view.frame.width)
  }
}

这个里面其实定义了一个scrollView, if #available(iOS 11.0, *) 这个是为了适配ios11,估计是ios11 多了一个safeArea的概念,

height:view.frame.height - view.safeAreaInsets.bottom - view.safeAreaInsets.top

height: view.frame.height - topLayoutGuide.length - bottomLayoutGuide.length

scrollView两个height 在不同系统中不同的计算方式,最后设定了scrollView的contentSize,scrollView的frame 和contentSize的概念在之后的文章中会讲到

import Foundation

class Product {
  var name: String?
  var cellImageName: String?
  var fullscreenImageName: String?
  
  init(name: String, cellImageName: String, fullscreenImageName: String) {
    self.name = name
    self.cellImageName = cellImageName
    self.fullscreenImageName = fullscreenImageName
  }
}

这个类,类似于java中的model类,没啥好说的

最后说一下一个注意点
在这里插入图片描述
这里需要按住ctrl+左键点击图片拖拽到本身上来设置一个aspect的ratio,不然会在iphone8以上的设备中不适配屏幕宽度,constraints设置好才能在不同的iphone设备之间达到好的显示效果。

那么这个p1先到这里,未完待续。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值