Mục đích:
- Hiểu được 1 số override methods hay dùng của UITableViewDelegate và UITableViewDataSourse
- Cách load dữ liệu từ 1 file .plist bất kỳ
Yêu cầu ở View 1 lấy ra được các tên quốc gia(country) cùng thuộc 1 châu lục nằm trong 1 Section.Sau đó ở view 2 đưa ra thông tin chi tiết của quốc gia đó.
Ta sẽ tạo 1 mảng kiểu Dictionary với key là các châu lục - value là 1 mảng Obj_Country.Mỗi Object trong mảng đó chứa 3 biến (country,capital,flag)
Để lấy ra được số lượng section ta sẽ lấy số lượng của 1 mảng mới với giá trị là tên các châu lục.
//MARK:: Parameters - User
var continent_Array = [String]() // Mảng lưu tên các Châu lục -> tạo section cho TableView
var country_Dict = NSMutableDictionary() // Dictionary lưu key là Continent(Các châu lục) với value tương ứng là 1 mảng Object Coutry(tên nước,thủ đô,cờ)
func loadDataFromPlist(){
var path : String = ""
path = Bundle.main.path(forResource: "Data", ofType: "plist")!
let dataArray: NSArray! = NSArray(contentsOfFile: path)
for i in 0 ..< dataArray.count{
let dict = dataArray[i] as! NSDictionary
let continent = dict.value(forKey: "continent") as! String
self.continent_Array.append(continent)
let country_Obj = dict.value(forKey: "countries") as! NSArray
self.country_Dict.setValue(country_Obj, forKey: continent)
}
}
// Trả về số lượng Section
override func numberOfSections(in tableView: UITableView) -> Int {
return continent_Array.count
}
// Trả về số lượng Row(Hàng) trong Section
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectiontitle = continent_Array[section]
let sectionObject = country_Dict.object(forKey: sectiontitle) as! NSArray
return sectionObject.count
}
// Hiển thị dữ liệu cho từng Cell trong mỗi hàng(Row)
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
if(cell == nil) {
cell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "Cell")
}
// Lấy ra châu lục mà tương ứng với section
let sectionTitle = continent_Array[indexPath.section]
// Lấy ra Mảng Obj_Country thông qua key(Châu lục-Continent) ứng với nó
let sectionValueCountry = country_Dict[sectionTitle] as! NSArray
// Lấy ra 1 cái Obj_Country
let countryObject = sectionValueCountry[indexPath.row] as! NSDictionary
cell.textLabel?.text = countryObject.value(forKey: "country") as! String?
return cell
}
// Hiển thị tên mục Section
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return continent_Array[section]
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
view.tintColor = UIColor.gray
let header: UITableViewHeaderFooterView = view as! UITableViewHeaderFooterView
header.textLabel?.textColor = UIColor.white
}
-
// Dùng Segue để truyền dữ liệu qua ViewDetail override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if(segue.identifier == "ShowDetail") { let detailVC = segue.destination as! ViewDetail let selectedRowIndex: IndexPath = self.tableView.indexPathForSelectedRow! let sectionTitle = continent_Array[selectedRowIndex.section] let sectionValueCountry = country_Dict[sectionTitle] as! NSArray let countryObject = sectionValueCountry[selectedRowIndex.row] as! NSDictionary detailVC.dictCountry = countryObject as! NSMutableDictionary } }
Để expand và collapse section thì chúng ta phải bắt được sự kiện khi người dùng bấm vào Section.Tuy nhiên thằng Apple chưa có hàm sẵn cho chúng ta nên chúng ta phải Custom 1 class mới để giải quyết được vấn đề này.
Class này được kế thừa từ class UITableViewHeaderFooterView.Vì class này cho phép người dùng có thể thêm thông tin trong Section.
Trong Class này sẽ có 2 parameters: 1 là biến section để xác định thứ tự của Section khi người dùng bấm vào.2 là biến để bắt được sự kiện người dùng bấm vào.
Tạo 1 protocol có func với 2 đầu vào là : 1 biến với kiểu là 1 class trên và biến với kiểu Int để xác định thứ tự trong section
Code
class ExpandableHeaderView: UITableViewHeaderFooterView {
var delegate: ExpandableHeaderViewDelegate?
var section: Int!
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(selectHeaderAction)))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func selectHeaderAction(gestureRecognizer: UITapGestureRecognizer) {
let cell = gestureRecognizer.view as! ExpandableHeaderView
delegate?.toggleSection(header: self, section: cell.section)
}
func customInit(title: String, section: Int, delegate: ExpandableHeaderViewDelegate) {
self.textLabel?.text = title
self.section = section
self.delegate = delegate
}
override func layoutSubviews() {
super.layoutSubviews()
self.textLabel?.textColor = UIColor.white
self.contentView.backgroundColor = UIColor.darkGray
}
}
///////////////////////////////////////////////////////////
protocol ExpandableHeaderViewDelegate {
func toggleSection(header: ExpandableHeaderView, section: Int)
}
Ta sẽ có 1 biến lưu trạng thái expand/Collapse => nó chỉ có 2 trạng thái nên ta quy ước rằng expand là true và collapse là false
Do đó ở mảng lưu Section ta phải add thêm 1 biến để lưu trạng thái của nó.Quy ước lúc đầu sẽ là False cho tất cả.
Trong UiTableViewDatasourse có func heightForRowAt indexPath => Dùng cái này để cho nó Expand hay collapse hiển thị nội dung trong từng section
Để Expand thì mỗi lần ta phải update lại tableView bằng cách dùng tableview.reloadreloadRow cho từng cell trong section