我在Swift中創建動態視圖時遇到問題。但是,這個問題並沒有直接關係到Swift本身,而是一個面向對象的編程問題。如何以良好的OO設計以編程方式創建動態視圖
問題是我需要能夠動態添加其他視圖元素到視圖。而且我不確定我是否正確地做了。我的解決方案對我來說似乎過分。
爲了解決這個問題,我認爲裝飾模式是一個很好的選擇。除了更好地控制流程外,我還介紹了模板方法模式。
我有許多類定義默認的外觀和感覺在某些視圖控件,如標籤,TextFields和按鈕。下面你可以看到它是如何的一個大概的想法。
這裏是我的代碼:
class ViewElement{
// this class inherits from default UIKit elemnts and provides default UI view
}
// default cell is the cell that implements default elements layout and margings, etc
class DefaultCell: UITableViewCell {
let mainStack: UIViewStack
func addElement(ViewElement)
}
class BlueCell: DefaultCell {
let textField1: TextField
let label : Label
let button: Button
init(){
textField = TextField()
label = Label()
button = Button()
addElement(textField)
addElement(label)
addElement(button)
}
}
這裏是tableViewDataSource實施
class BlueTable: UITableViewDataSource {
...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: = dequeue the cell
if cell == nil {
cell = BlueCell(with everything I want to pass to the constructor)
}
// then I check for the condition
switch weather {
case good:
labelOne
labelTwo
buttonOne
cell.addElement(labelOne)
cell.addElement(labelTwo)
cell.addElement(buttonOne)
case bad:
// idem
cell.addView(badWeatherView)
}
return cell
}
}
正如你所看到的,條件的數量越多,越大我的switch語句。
由於我需要訪問我在條件中分配的其他元素,例如回調,點擊事件等,還有一個事實,即通過addElement方法添加了條件中的那些元素,這意味着那些元素將被添加到mainStack的底部。
爲了有超過元素添加到堆棧的方式,我決定去與下面的解決方案控制:模板方法模式
protocol OrderableElements {
func top()
func middle()
func bottom()
}
extension OrderableElements {
func render() {
top()
middle()
bottom()
}
}
現在BLUECELL實現協議,看起來像這樣
class BlueCell: DefaultCell, OrderableElements {
init(){
textField = TextField()
label = Label()
button = Button()
}
func top() {
addElement(textField)
}
func middle() {
addElement(label)
}
func bottom(){
addElement(button)
}
}
的tabledatasource類,然後將如下所示:
class BlueTable: UITableViewDataSource {
...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: = dequeue the cell
if cell == nil {
cell = BlueCell(with everything I want to pass to the constructor)
}
// then I check for the condition
switch weather {
case good:
labelOne
labelTwo
buttonOne
cell.addElement(labelOne)
cell.addElement(labelTwo)
cell.addElement(buttonOne)
case bad:
// idem
cell.addView(badWeatherView)
}
...
**cell.render()**
return cell
}
}
現在,因爲我需要BLUECELL的範圍過程中添加新的視圖元素在特定位置或更好說,在某些時刻,我介紹了裝飾的細胞,就像這樣:
class CellDecorator: OrderableElements {
var cell: BlueCell
init(cell: BlueCell){
self.cell = cell
}
func top() {
self.cell.top()
}
func middle(){
self.cell.middle()
}
func bottom(){
self.cell.bottom()
}
func getCell() {
return self.cell
}
}
下面是具體的實現
class GoodWeatherDecorator: CellDecorator {
let goodLabel
let goodTextField
let goodButton
override top() {
super.top()
addElement(goodLabel)
}
override middle(){
super.middle()
addElement(goodTextfield)
}
override bottom(){
super.bottom()
addElement(goodButton)
}
}
最終實現cellForRowAt方法看起來象下面這樣:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: = dequeue the cell
if cell == nil {
cell = BlueCell(with everything I want to pass to the constructor)
}
// then I check for the condition
var decoratedCell = CellDecorator(cell: cell)
switch weather {
case good:
decoratedCell = GoodWeatherDecorator(cell: cell)
case bad:
decoratedCell = BadWeatherDecorator(cell: cell)
}
decoratedCell.configure() // <------------ here is the configure call
cell = decoratedCell.getCell() // <------- here I get cell from the decorator
return cell
}
}
現在我明白,我的第執行的e裝飾器模式不是100%有效的,因爲我沒有從BlueCell類繼承,例如。但那並不會讓我感到困擾。困擾我的事情是,我認爲解決這個問題的方法有點矯枉過正。
所有的作品都是正確的,但我可以幫助解決這個微不足道的問題。
您認爲如何?你將如何解決這類問題?在advace
感謝
嗨,謝謝你的回答。我應該提到,我將有15個額外的視圖組件(元素)應該添加到此容器中。 我同意你的建議,移動容器視圖內的條件,並決定顯示哪些附加元素。但再一次,因爲即使隱藏在tableViewDataSource中,我的條件仍然會有很大的差異,幾乎無法管理。 – DS888
所有更多的理由這樣做,因爲我在這個答案建議。 –