๐Ÿ“‘ Project

[ Project ] todoList ๊ตฌํ˜„ํ•˜๊ธฐ #2

EarthSea 2024. 3. 19. 23:20

 

 

 

 

์•ˆ๋…•ํ•˜์„ธ์š”๐Ÿ’š

์–ด์ œ๋Š” todolist๋ฅผ ๋ณด์—ฌ์ค„ ํ…Œ์ด๋ธ”๋ทฐ๊ณผ todolist์˜ ์™„๋ฃŒ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋Š” ์ฒดํฌ ๋ฐ•์Šค ๋ฒ„ํŠผ์„ ๊ตฌํ˜„ํ•˜์˜€๋Š”๋ฐ์š”.

[ Project ] todoList ๊ตฌํ˜„ํ•˜๊ธฐ #1 

 

[ Project ] todoList ๊ตฌํ˜„ํ•˜๊ธฐ #1

์•ˆ๋…•ํ•˜์„ธ์š”! ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ๋Š” todoList ๊ตฌํ˜„์ž…๋‹ˆ๋‹ค. ์˜ค๋Š˜์€ todolist๋ฅผ ๋ณด์—ฌ์ค„ ํ…Œ์ด๋ธ”๋ทฐ์™€ ์™„๋ฃŒ์‹œ ์ฒดํฌํ•  ๋ฒ„ํŠผ์„ ๊ตฌํ˜„ํ•ด๋ณด์•˜์–ด์š” ๐ŸŒป ํ…Œ์ด๋ธ” ๋ทฐ๋ฅผ ์‚ฌ์šฉํ•œ todoList ๊ตฌํ˜„ํ•˜๊ธฐ UI ๊ตฌ์„ฑ ๋”๋ณด๊ธฐ View Todo List L

jihae-qu.tistory.com

 

 

 

์˜ค๋Š˜์€ ์ทจ์†Œ์„  ๊ตฌํ˜„๊ณผ todolist์— ๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ edit ๋ฒ„ํŠผ๊ณผ add ๋ฒ„ํŠผ์„ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฐ์ดํ„ฐ ๋งค๋‹ˆ์ € ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋ฐ์ดํ„ฐ๋„ ๋ถ„๋ฆฌ๋ฅผ ํ•ด์ฃผ๊ณ ,
todolist์˜ ์ •๋ ฌ์„ ๋ฐ”๊พธ์–ด์ฃผ๋Š” ๊ธฐ๋Šฅ๋„ ๊ตฌํ˜„์„ ํ•ด๋ณด์•˜์–ด์š”!!

์‹œ์ž‘ํ•ด ๋ด…์‹œ๋‹คโœจ

 

์ทจ์†Œ์„  ๊ตฌํ˜„

todo ์™„๋ฃŒ ์‹œ์— ์™„๋ฃŒํ•œ ๋ถ€๋ถ„๊ณผ ๋ฏธ์™„๋ฃŒํ•œ ๋ถ€๋ถ„์˜ ๊ตฌ๋ถ„์„ ์œ„ํ•ด์„œ ์ทจ์†Œ์„ ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ๊ธ€๊ผด ์ƒ‰์„ ๋ฐ”๊พธ์–ด์ฃผ์—ˆ์–ด์š”.

์šฐ์„  ์ทจ์†Œ์„ ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” AttributedString์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค!

 

 

AttributedString์ด๋ž€?

๋ฌธ์ž์—ด, ๋ฌธ์ž์—ด ๊ฐ๊ฐ์˜ ์š”์†Œ, ๋ฌธ์ž์—ด์˜ ๋ฒ”์œ„์™€ ๊ด€๋ จ๋œ ์†์„ฑ์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฌธ์ž์—ด๊ณผ ๊ด€๋ จ๋œ ์†์„ฑ์€ ํฐํŠธ๋‚˜ ํฐํŠธ์˜ ์‚ฌ์ด์ฆˆ, ํฐํŠธ ์‚ฌ์ด์˜ ๊ฐ„๊ฒฉ, ํฐํŠธ ์ƒ‰์ƒ ๋“ฑ๋“ฑ์„ ์ด์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ NSAttributedString ๋Š” ์ฝ๊ธฐ ์ „์šฉ ์†์„ฑ ๋ฌธ์ž์—ด์— ๋Œ€ํ•œ, NSMutableAttributedString ์€ ์ˆ˜์ • ๊ฐ€๋Šฅํ•œ ์†์„ฑ ๋ฌธ์ž์—ด์— ๋Œ€ํ•œ ํ”„๋กœ๊ทธ๋žจ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.

 

 

์–ด์จŒ๋“  NSAttributedString์€ ๋ฌธ์ž์—ด์˜ ์†์„ฑ์„ ๋ณด์—ฌ์ฃผ๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑฐ์ฃ !

 

 

[ NSAttributedString์˜ key ์ข…๋ฅ˜ ]

๋”๋ณด๊ธฐ

 

static let attachment: NSAttributedString.Key
The attachment for the text.
 
static let backgroundColor: NSAttributedString.Key
The color of the background behind the text.
 
static let baselineOffset: NSAttributedString.Key
The vertical offset for the position of the text.
 
static let expansion: NSAttributedString.Key
The expansion factor of the text.
Deprecated
 
static let glyphInfo: NSAttributedString.Key
The name of a glyph info object.
 
static let kern: NSAttributedString.Key
The kerning of the text.
 
static let ligature: NSAttributedString.Key
The ligature of the text.
 
static let link: NSAttributedString.Key
The link for the text.
 
static let markdownSourcePosition: NSAttributedString.Key
The position in a Markdown source string corresponding to some attributed text.
 
static let markedClauseSegment: NSAttributedString.Key
The index of the marked clause segment.
 
static let obliqueness: NSAttributedString.Key
The obliqueness of the text.
Deprecated
 
static let paragraphStyle: NSAttributedString.Key
The paragraph style of the text.
 
static let shadow: NSAttributedString.Key
The shadow of the text.
 
static let spellingState: NSAttributedString.Key
The spelling state of the text.
 
static let strikethroughColor: NSAttributedString.Key
The color of the strikethrough.
 
static let strikethroughStyle: NSAttributedString.Key
The strikethrough style of the text.
 
static let superscript: NSAttributedString.Key
The superscript of the text.
 
static let textAlternatives: NSAttributedString.Key
The alternatives for the text.
 
static let underlineStyle: NSAttributedString.Key
The underline style of the text.
 
static let verticalGlyphForm: NSAttributedString.Key
The vertical glyph form of the text.
Deprecated
 
static let writingDirection: NSAttributedString.Key
The writing direction of the text.
 
์ถœ์ฒ˜ : https://developer.apple.com/documentation/foundation/nsattributedstring/key ์—์„œ ๋ฐœ์ทŒ

 

์—ฌ๊ธฐ์„œ ์ทจ์†Œ์„ ์„ ๊ตฌํ˜„ํ•˜๋Š” ์š”์†Œ๋Š” strikethroughStyle ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ „ String์ด๋ผ๋Š” ๋ฌธ์ž์—ด์„ ํ™•์žฅํ•˜์—ฌ ๋ฌธ์ž์—ด์— ์ทจ์†Œ์„ ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์„ ์–ธํ•˜์˜€์–ด์š”.

 

extension String {
    func strikeThrough() -> NSAttributedString {
        let attributeString = NSMutableAttributedString(string: self)
        attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: NSMakeRange(0, attributeString.length))
        return attributeString
    }
}

 

attributeString์ด๋ผ๋Š” ๋ณ€์ˆ˜์— NSMutableAttributedString(String: self) ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ํ•ด๋‹น ์ธ์Šคํ„ด์Šค์˜ ๋‚ด๋ถ€ ํ•จ์ˆ˜์ธ addAttribute ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์ทจ์†Œ์„  ์Šคํƒ€์ผ์„ ์ ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

todo๋ฅผ ์™„๋ฃŒํ•˜์˜€์„ ๋•Œ, ์ฒดํฌ ๋ฐ•์Šค๊ฐ€ ์ฒดํฌ๋˜๊ณ  ํ•ด์ œ๋จ์— ๋”ฐ๋ผ ์ทจ์†Œ์„ ๋„ ๊ทธ์–ด์ง€๊ณ , ์ œ๊ฑฐ๋ผ์•ผ ํ•˜๋‹ˆ ์ทจ์†Œ์„ ์ด ์ง€์›Œ์กŒ์„ ๋•Œ์˜ ๋ฉ”์„œ๋“œ๋„ ๊ตฌํ˜„์„ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

extension String {
  func removeStrikeThrough() -> NSAttributedString {
        let attributeString = NSMutableAttributedString(string: self)
        attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: 0 , range: NSMakeRange(0, attributeString.length))
        return attributeString
    }
}

 

์ด์ œ ์ทจ์†Œ์„ ์„ ๋Œ€์ž…ํ•ด ๋ด…์‹œ๋‹ค. ์–ด์ œ ๊ตฌํ˜„ํ•œ checkButton์ด ์„ ํƒ๋˜๊ณ  ํ•ด์ œ๋จ์— ๋”ฐ๋ผ ๋ณ€ํ™”์‹œ์ผฐ๋˜ checkButtonTapped ํ•จ์ˆ˜์— ์ ์šฉ์„ ํ•ด๋ณด์•˜์–ด์š”. sender.isSelected ๊ฐ€ true๋ผ๋Š” ๊ฒƒ์€ Selected ํ•จ์ˆ˜๊ฐ€ ํ™œ์„ฑํ™”๋˜์—ˆ์„ ๋•Œ์ด๋ฏ€๋กœ checkButton์„ ๋ˆ„๋ฅด๋ฉด ๋น„ํ™œ์„ฑํ™” ์ƒํƒœ๋กœ ๋‹ค์‹œ ๋งŒ๋“ค์–ด์•ผ๊ฒ ์ฃ ?ใ…Ž

 

	@IBAction func checkButtonTapped(_ sender: UIButton) {
        if sender.isSelected {
            sender.isSelected = false
            todoText.textColor = UIColor.black
            todoText.font = UIFont.systemFont(ofSize:18)
            todoText.attributedText = todoText.text?.removeStrikeThrough()
        }else {
            sender.isSelected = true
            todoText.textColor = UIColor.darkGray
            todoText.font = UIFont.systemFont(ofSize:18)
            todoText.attributedText = todoText.text?.strikeThrough()
        }
    }

 

์ถ”๊ฐ€์ ์œผ๋กœ ํฐํŠธ์˜ ์ƒ‰์ƒ๋„ ๋ณ€๊ฒฝ์„ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

 

๊ตฌํ˜„ํ•œ ํ™”๋ฉด

์ฒดํฌ ๋ฐ•์Šค ํด๋ฆญ์‹œ ์ทจ์†Œ์„  ์ƒ์„ฑ / ํ•ด์ œ์‹œ ์ตœ์†Œ์„  ํ•ด์ œ

 

 

 

๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•œ Edit ๋ฒ„ํŠผ๊ณผ Add ๋ฒ„ํŠผ ๊ตฌํ˜„

 

์šฐ์„  ๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋ถ€ํ„ฐ ์ถ”๊ฐ€ํ•ด ๋ด…์‹œ๋‹ค.

 

[ ๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ ์ถ”๊ฐ€ ๋ฐฉ๋ฒ• ]

๋”๋ณด๊ธฐ

์ด๋ฏธ ๋ฉ”์ธํ™”๋ฉด์„ ๊ตฌํ˜„ํ•œ ๋’ค์— ๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์„ค์น˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ด…์‹œ๋‹ค!

์šฐ์„  Main.storyboard์—์„œ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์€ ํ™”๋ฉด์˜ ViewController๋ฅผ ํด๋ฆญํ•œ ๋‹ค์Œ

์˜ค๋ฅธ์ชฝ ์•„๋ž˜์˜ ํ•˜๋‹จ์— ๋นจ๊ฐ„ ํ…Œ๋‘๋ฆฌ ์•„์ด์ฝ˜์„ ํด๋ฆญํ•œ ํ›„ Navigation Controller๋ฅผ ๋ˆŒ๋Ÿฌ์ฃผ๋ฉด ๋์ž…๋‹ˆ๋‹ค!

 

๋„ค๋น„๊ฒŒ์ด์…˜ Controller๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค๋ฉด, ์ด์ œ Edit ๋ฒ„ํŠผ์„ ์ƒ์„ฑํ•ด์•ผ๊ฒ ์ฃ ?!

์ด๊ฒƒ๋„ ์•„์ฃผ์•„์ฃผ ์‰ฌ์›Œ์š”!!

 

[ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”์— ๋ฒ„ํŠผ ์ถ”๊ฐ€ํ•˜๊ธฐ ]

๋”๋ณด๊ธฐ

 

 shift + cmd + L  ๋‹จ์ถ•ํ‚ค ๋ˆŒ๋Ÿฌ ์•„๋ž˜์˜ ํ™”๋ฉด์ด ๋œฌ๋‹ค๋ฉด ๊ฒ€์ƒ‰์ฐฝ์— button ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค!

Bar Button Item์„ ๋“œ๋ž˜๊ทธํ•˜์—ฌ Navigation Item ์•„๋ž˜์— ์œ„์น˜ํ•˜๋„๋ก ์žก์€ ํ›„ ๋†“๊ธฐ

 

์œ„์˜ ๊ทธ๋ฆผ๋Œ€๋กœ ์ถœ๋ ฅ์ด ๋˜์—ˆ๋‹ค๋ฉด, ์•„๋งˆ Right Bar Button Items ์—๋Š” ์ด๋ฏธ ๋ฒ„ํŠผ์ด ํ•˜๋‚˜๊ฐ€ ์žˆ์„ ๊ฑฐ์˜ˆ์š”!

๋งŒ์•ฝ ์—†๋‹ค๋ฉด ์œ„์˜ ๋ฐฉ๋ฒ•์„ ๋˜‘๊ฐ™์ด ํ•˜์—ฌ Bar Button Items์„ Left Bar Button Items ์•„๋ž˜๋‚˜ Right Bar Button Items ์•„๋ž˜์— ์ถ”๊ฐ€ํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค!!

 

์ €๋Š” ์˜ค๋ฅธ์ชฝ์— Edit ๋ฒ„ํŠผ์„ ์™ผ์ชฝ์— Add ๋ฒ„ํŠผ์„ ์ถ”๊ฐ€ํ•˜์˜€์–ด์š”!

 

Edit ๋ฒ„ํŠผ ๊ตฌํ˜„ํ•˜๊ธฐ

  • Editting ๋ชจ๋“œ๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ
  • Editting ๋ชจ๋“œ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ, ๋ฒ„ํŠผ ์ด๋ฆ„ ๋ณ€๊ฒฝํ•˜๊ธฐ

 

 

๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์€ Edit ๋ฒ„ํŠผ์„ ํด๋ฆญํ•œ ํ›„ Attribute ๋ฐ”์˜ System Item ์„ Edit ๋กœ ๊ตฌํ˜„ํ•˜๋ฉด ๋˜๋Š”๋ฐ์š”! ์ €๋Š” Edit ๋ฒ„ํŠผ์ด ํด๋ฆญ๋˜์—ˆ์„ ๋•Œ Done์œผ๋กœ ํ…์ŠคํŠธ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์–ด์„œ System Item ์„ Custom ์œผ๋กœ Bar Item์˜ Title์„ "Edit"์œผ๋กœ ๋ณ€๊ฒฝํ•ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

EditButton์„ ๋ˆŒ๋ €์„ ๋•Œ Editing ๋ชจ๋“œ์™€ Edit ๋ฒ„ํŠผ์˜ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•ด ์ฃผ๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ•ด๋‹น ๋ฒ„ํŠผ๊ณผ @IBOutlet / @IBAction์„ ์—ฐ๊ฒฐ์„ ํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 

 

class ViewController: UIViewController {
    
    // editButton ์—ฐ๊ฒฐ
    @IBOutlet weak var editButton: UIBarButtonItem!
    
    @IBOutlet weak var date: UILabel!
    @IBOutlet weak var tableview: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setting()
        setTitle()
    }
    
    // edit Button์ด ๋ˆŒ๋ ธ์„ ๋•Œ ๋ฒ„ํŠผ ์ด๋ฆ„ ๋ณ€๊ฒฝํ•˜๊ธฐ -> ์ถ”๊ฐ€๋ชจ๋“œ๋กœ ๋ณ€ํ™˜
    @IBAction func editButtonTapped(_ sender: UIBarButtonItem) {
        if self.tableview.isEditing {
            // editing ๋ชจ๋“œ ๋น„ํ™œ์„ฑํ™”
            self.editButton.title = "Edit"
            self.tableview.setEditing(false, animated: true)
        } else {
            // editing ๋ชจ๋“œ ํ™œ์„ฑํ™”
            self.editButton.title = "Done"
            self.tableview.setEditing(true, animated: true)
        }
    }
    
}

 

์œ„์˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด ๋ฒ„ํŠผ๊ณผ ViewController๋ฅผ ์—ฐ๊ฒฐํ•˜๊ณ , ๋ฒ„ํŠผ์ด ๋ˆŒ๋ ธ์„ ๋•Œ Editing ๋ชจ๋“œ๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

์ถ”๊ฐ€์ ์ธ ์ฝ”๋“œ ์„ค๋ช…์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

  • self.tableview.isEditing
    : ํ…Œ์ด๋ธ” ๋ทฐ๊ฐ€ editing ๋ชจ๋“œ์ธ์ง€ ์•„๋‹Œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๊ฑฐ๋‚˜ ์ž…๋ ฅํ•˜๋Š” ์š”์†Œ

 

  • self.editButton.title = "Edit"
    : ๋ฒ„ํŠผ์˜ title์„ ๋ณ€๊ฒฝ

 

  • self.tableview.setEditing(true, animated: true) 
    : ํ…Œ์ด๋ธ” ๋ทฐ๋ฅผ Editing ๋ชจ๋“œ๋กœ ํ™œ์„ฑํ™”

 

 

๊ตฌํ˜„ํ•œ ํ™”๋ฉด

edit ๋ฒ„ํŠผ์ด ํด๋ฆญ๋จ์— ๋”ฐ๋ผ editing ํ™”๋ฉด์œผ๋กœ ์ „ํ™˜

 

 

 

Add ๋ฒ„ํŠผ ๊ตฌํ˜„ํ•˜๊ธฐ

  • Editing ๋ชจ๋“œ์ผ ๋•Œ๋งŒ Add ๋ฒ„ํŠผ ๋ณด์ด๊ธฐ

 

์œ„์˜ Edit ๋ฒ„ํŠผ์„ ๊ตฌํ˜„ํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•˜๊ฒŒ Add ๋ฒ„ํŠผ์„ ๊ตฌํ˜„ํ•ด ๋ด…์‹œ๋‹ค!

 

 

๊ทธ๋ฆผ์—์„œ ๋ณด์ด์ง€๋Š” ์•Š์ง€๋งŒ Edit ๋ฒ„ํŠผ ๋ฐ˜๋Œ€ํŽธ์— Add ๋ฒ„ํŠผ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ๋ณด์ด์ง€ ์•Š๋Š” ์ด์œ ๋Š” ์ œ๊ฐ€ Drawing ์— Hidden ์„ ์ฒดํฌํ•ด ๋’€๊ธฐ ๋•Œ๋ฌธ์ธ๋ฐ์š”?! ์ €๋Š” Edit ๋ชจ๋“œ์ผ ๋•Œ๋งŒ todo ๋ฆฌ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์—ˆ์œผ๋ฉด ์ข‹๊ฒ ์–ด์„œ ๊ธฐ๋ณธ ํ™”๋ฉด์—์„œ๋Š” ๋ฒ„ํŠผ์„ ์ˆจ๊ฒจ๋‘์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  System Item ์—์„œ Add ๋ฅผ ์„ ํƒํ•ด ์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค!

 

class ViewController: UIViewController {
    
    @IBOutlet weak var editButton: UIBarButtonItem!
    @IBOutlet weak var addButton: UIBarButtonItem!

    @IBOutlet weak var date: UILabel!
    @IBOutlet weak var tableview: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        dataManager.makeListData()
        setting()
    }
    
    // edit Button์ด ๋ˆŒ๋ ธ์„ ๋•Œ ๋ฒ„ํŠผ ์ด๋ฆ„ ๋ณ€๊ฒฝํ•˜๊ธฐ -> ์ถ”๊ฐ€๋ชจ๋“œ๋กœ ๋ณ€ํ™˜
    @IBAction func editButtonTapped(_ sender: UIBarButtonItem) {
        if self.tableview.isEditing {
            // editing ๋ชจ๋“œ ๋น„ํ™œ์„ฑํ™”
            self.editButton.title = "Edit"
            self.tableview.setEditing(false, animated: true)
            // addButton ๋น„ํ™œ์„ฑํ™” / ์ˆจ๊ธฐ๊ธฐ
            self.addButton.isEnabled = false
            self.addButton.isHidden = true
        } else {
            // editing ๋ชจ๋“œ ํ™œ์„ฑํ™”
            self.editButton.title = "Done"
            self.tableview.setEditing(true, animated: true)
            // addButton ํ™œ์„ฑํ™” / ๋ณด์ด๊ธฐ
            self.addButton.isEnabled = true
            self.addButton.isHidden = false
        }
    }
    
    // add Button์ด ๋ˆŒ๋ ธ์„ ๋•Œ ์–ผ๋Ÿฟ์ฐฝ ๋„์šฐ๊ธฐ
    @IBAction func addButtonTapped(_ sender: UIBarButtonItem) {
        
    }
}

 

์œ„์˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด ํ•ด๋‹น Add ๋ฒ„ํŠผ๊ณผ @IBOutlet / @IBAction ์„ ์—ฐ๊ฒฐ์„ ํ•ด์ฃผ์‹œ๊ณ ์š”! ์šฐ์„  ์œ„์—์„œ ๊ตฌํ˜„ํ–ˆ๋˜ editButtonTapped ํ•จ์ˆ˜์— ๊ฐ๊ฐ editing์ด ํ™œ์„ฑํ™”๋˜๊ณ  ๋น„ํ™œ์„ฑํ™”๋˜์—ˆ์„ ๋•Œ, add๋ฒ„ํŠผ์„ ํ™œ์„ฑํ™”ํ•˜๊ณ  ๋ณด์ด๋„๋ก!  add๋ฒ„ํŠผ์ด ๋น„ํ™œ์„ฑํ™”๋˜๊ณ  ๋ณด์ด์ง€ ์•Š๋„๋ก ๊ตฌํ˜„์„ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

  • self.addButton.isEnabled
    : ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™”๋˜๋Š”์ง€ ์•ˆ ๋˜๋Š” ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๊ฑฐ๋‚˜ ์ž…๋ ฅ๋ฐ›๋Š” ์š”์†Œ

 

  • self.addButton.isHidden
    : ๋ฒ„ํŠผ์˜ ์ˆจ๊น€๋ชจ๋“œ๋ฅผ ํ™œ์„ฑํ™”ํ–ˆ๋Š”์ง€ ์•ˆ ํ–ˆ๋Š” ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๊ฑฐ๋‚˜ ์ž…๋ ฅ๋ฐ›๋Š” ์š”์†Œ

 

๊ตฌํ˜„ํ•œ ํ™”๋ฉด

Edit ๋ฒ„ํŠผ ๋ˆŒ๋ €์„ ๋•Œ add ๋ฒ„ํŠผ ํ™œ์„ฑํ™”
Done ๋ฒ„ํŠผ์ด ๋ˆŒ๋ €์„ ๋•Œ add ๋ฒ„ํŠผ ๋น„ํ™œ์„ฑํ™”

 

 

Add ๋ฒ„ํŠผ ๋ˆŒ๋ ธ์„ ๋•Œ ์–ผ๋Ÿฟ์ฐฝ ๋„์šฐ๊ธฐ

Add Button์ด ๋ˆŒ๋ ธ์„ ๋•Œ, todoList๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์–ผ๋Ÿฟ์ฐฝ์„ ๊ตฌํ˜„ํ•ด ๋ด…์‹œ๋‹ค. ์–ผ๋Ÿฟ์ฐฝ์—๋Š” title๊ณผ message์™€ ํ…์ŠคํŠธ ํ•„๋“œ๊ฐ€ ๋‚˜์˜ค๊ณ  ํ™•์ธ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ…์ŠคํŠธ ํ•„๋“œ๊ฐ€ ์ถ”๊ฐ€๊ฐ€ ๋˜๊ณ , ์ทจ์†Œ๋ฅผ ๋ˆ„๋ฅด๋ฉด ํ…์ŠคํŠธ ํ•„๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

    // add Button์ด ๋ˆŒ๋ ธ์„ ๋•Œ ์–ผ๋Ÿฟ์ฐฝ ๋„์šฐ๊ธฐ
    @IBAction func addButtonTapped(_ sender: UIBarButtonItem) {
    	// ์–ผ๋Ÿฟ Controller๋ฅผ ์‚ฌ์šฉํ•œ ์–ผ๋Ÿฟ์ฐฝ ์ƒ์„ฑ
        let alert = UIAlertController(title: "Add", message: "ํ•ด์•ผ ํ•  ์ผ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.",
                                      preferredStyle: .alert)
        alert.addTextField{ tf in
        	// ํ…์ŠคํŠธ ํ•„๋“œ ์•ˆ์˜ ๊ธ€
            tf.placeholder = "to do"
        }
        // ํ™•์ธ ์•ก์…˜ ๋ฒ„ํŠผ ์ƒ์„ฑ
        alert.addAction(UIAlertAction(title: "ํ™•์ธ", style: .default, handler: { _ in
            // ํ…์ŠคํŠธ ํ•„๋“œ ๊ธ€ ๋ฐ›์•„์˜ค๊ธฐ
            guard let text = alert.textFields?[0].text else {return}
            if text != "" {
            	// ๋ฐ์ดํ„ฐ ๋ฉ”๋‹ˆ์ €๋ฅผ ํ†ตํ•œ ๋ฆฌ์ŠคํŠธ ์—…๋ฐ์ดํŠธ
                self.dataManager.updateTodoListData(text)
                // ํ…Œ์ด๋ธ”๋ทฐ์˜ ๋ฐ์ดํ„ฐ ๋ฆฌ๋กœ๋“œ
                self.tableview.reloadData()
            }
        }))
        // ์ทจ์†Œ ์•ก์…˜ ๋ฒ„ํŠผ ์ƒ์„ฑ
        alert.addAction(UIAlertAction(title: "์ทจ์†Œ", style: .cancel, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }

 

์œ„์˜ addButtonTapped() ์ฝ”๋“œ์— ์–ผ๋Ÿฟ์ฐฝ์„ ์ถ”๊ฐ€ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์–ด๋–ค ์˜๋ฏธ์ธ์ง€ ์ฝ”๋“œ๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ ๋œฏ์–ด๋ด…์‹œ๋‹ค!

 

  • UIAlertController(title: "Add", message: "ํ•ด์•ผ ํ•  ์ผ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.", preferredStyle: .aleart)
    : UIAlertController๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์–ผ๋Ÿฟ์ฐฝ์„ ์ƒ์„ฑ
      title (์–ผ๋Ÿฟ์ฐฝ์˜ ์ด๋ฆ„), message (์–ผ๋Ÿฟ์ฐฝ์˜ ์ œ๋ชฉ ๋ฐ‘์— ๋“ค์–ด๊ฐˆ ๋ฉ”์‹œ์ง€ ๋ฌธ๊ตฌ), preferredStyle (. actionSheet์™€. alert ์ค‘ ์„ ํƒ)

       -. actionSheet : ํ™”๋ฉด์˜ ์•„๋ž˜์ชฝ์— ์œ„์น˜ํ•œ ์ฐฝ

       -. alert : ํ™”๋ฉด์˜ ์ค‘๊ฐ„์— ์œ„์น˜ํ•œ ์ฐฝ 

 

  • tf.placeholder = "to do"
    : ํ…์ŠคํŠธ ํ•„๋“œ์˜ placeholder ์„ค์ •
      placeholder๋ž€? ํ…์ŠคํŠธ๋ฅผ ์ ๊ธฐ ์ „์— ๋ณด์ด๋Š” ๊ธ€

 

  • alert.addTextField {}
    : ์–ผ๋Ÿฟ ์ฐฝ์— TextField ์ถ”๊ฐ€

 

  • alert.addAction()
    : ์–ผ๋Ÿฟ ์ฐฝ์— Action ์ถ”๊ฐ€

 

  • UIAlertAction(title: "ํ™•์ธ", style:. default, handler: { ํด๋กœ์ € })
    : UIAlertAction ์ถ”๊ฐ€
      title (์–ผ๋Ÿฟ ์•ก์…˜์˜ ์ด๋ฆ„), style (. default,. cancel,. destructive ์ค‘ ์„ ํƒ ), handler(๋ฒ„ํŠผ์œผ๋กœ ์ธํ•ด ์ˆ˜ํ–‰๋  ์ž‘์—… ์ฝ”๋“œ ์ถ”๊ฐ€)
    -. default : ์ผ๋ฐ˜์ ์ธ ์ฝ”๋“œ
    -. cancel : ์‹คํ–‰ ์ทจ์†Œ
    -. destructice : ๊ฐ•์กฐํ•˜๋Š” ์ฝ”๋“œ๋กœ ๊ธ€์”จ ์ƒ‰์ƒ์ด ๋‹ค๋ฆ„

 

  • alert.textFields?[0].text
    : TextFields ๋ž€์˜ 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•œ ๋ฌธ์ž์—ด ์ถ”์ถœ

 

  • self.tableview.reloadData()
    : tableview ๋‹ค์‹œ ๋ฆฌ๋กœ๋“œ

 

  • self.present(alert, animated: true, completion: nil)
    : ์–ผ๋Ÿฟ์ฐฝ ๋„์šฐ๊ธฐ

 

 

๊ตฌํ˜„ํ•œ ํ™”๋ฉด

todolist ์ถ”๊ฐ€ํ•˜๊ธฐ ๋ฒ„ํŠผ
todo list ์ทจ์†Œํ•˜๊ธฐ ๋ฒ„ํŠผ

 

 

 

ListDataManager ํด๋ž˜์Šค ์ƒ์„ฑ

: ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๊ด€ํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ListDataManager ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์™ธ๋ถ€์—์„œ todoList ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๋„๋ก private๋กœ ๊ตฌํ˜„ํ•˜๊ณ , ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

class ListDataManager {
    private var todoListDataArray: [TodoData] = []
    
    func makeListData() {
        todoListDataArray = [
            TodoData(id: 0, title: "์˜ค์ด์‚ฌ๊ธฐ", isChecked: false),
            TodoData(id: 1, title: "ํ—ค๋“œ์…‹๊ณ ์น˜๊ธฐ", isChecked: false),
            TodoData(id: 2, title: "์ฑ…์‚ฌ๊ธฐ", isChecked: false),
            TodoData(id: 3, title: "์˜์–‘์ œ ๋จน๊ธฐ", isChecked: false),
            TodoData(id: 4, title: "๋ณ‘์› ๋ฐฉ๋ฌธ", isChecked: false),
            TodoData(id: 5, title: "๋ฌผ 2L ๋งˆ์‹œ๊ธฐ", isChecked: false),
            TodoData(id: 6, title: "๊ฐ•์•„์ง€ ์‚ฐ์ฑ… ์‹œํ‚ค๊ธฐ", isChecked: false),
            TodoData(id: 7, title: "์ž๊ธฐ์†Œ๊ฐœ ํ•˜๊ธฐ", isChecked: false),
            TodoData(id: 8, title: "iOS ๊ฐ•์˜๋“ฃ๊ธฐ", isChecked: false),
            TodoData(id: 9, title: "TIL ์ž‘์„ฑํ•˜๊ธฐ", isChecked: false),
            TodoData(id: 10, title: "์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฌธ์ œ ํ’€๊ธฐ", isChecked: false),
            TodoData(id: 11, title: "์—ด๊ณตํ•˜๊ธฐ", isChecked: false),
        ]
    }
    
    func getTodoListData() -> [TodoData] {
        return todoListDataArray
    }
    
    func updateTodoListData(_ title: String) {
        let todo = TodoData(id: todoListDataArray.count + 1, title: title, isChecked: false)
        todoListDataArray.append(todo)
    }
    
    func deleteTodoListData(_ row: Int) {
        todoListDataArray.remove(at: row)
    }
    
    func insertTodoListData(_ row: Int, _ todoData: TodoData) {
        todoListDataArray.insert(todoData, at: row)
    }
}

 

 

 

๋„ค๋น„๊ฒŒ์ด์…˜ Title์— UI Lable ์ถ”๊ฐ€ํ•˜๊ธฐ

๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด์„œ ์›๋ž˜ ์žˆ๋˜ ์ œ๋ชฉ์ด ์•„๋ž˜๋กœ ๋ฐ€๋ ค๋‚˜๊ฒŒ ๋˜์–ด์„œ ๋„ค๋น„๊ฒŒ์ด์…˜์˜ Title์— UILable์„ ์ถ”๊ฐ€ํ•˜๊ณ  ๊ธฐ์กด์˜ todoList๋Š” ์‚ญ์ œ๋ฅผ ํ•ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

 

class ViewController: UIViewController {
	
    override func viewDidLoad() {
        super.viewDidLoad()
        dataManager.makeListData()
        setting()
        setTitle()
    }
    
	// ๋„ค๋น„๊ฒŒ์ด์…˜ title์— UILabel ์ถ”๊ฐ€ํ•˜๊ธฐ
    func setTitle() {
        let title = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 40))
        title.textAlignment = .center
        title.font = UIFont.init(name: "American Typewriter Bold", size: 29.0)
        title.text = "Todo List"
        self.navigationItem.titleView = title
    }
}

 

๋„ค๋น„๊ฒŒ์ด์…˜ title์— UILabel์„ ์ถ”๊ฐ€ํ•˜๋Š” setTitle() ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๊ณ  viewDidLoad() ํ•จ์ˆ˜์— ์ถ”๊ฐ€ํ•ด ์ค๋‹ˆ๋‹ค.

title์„ UILabel๋กœ ๊ตฌํ˜„ํ•˜์—ฌ ํฐํŠธ์™€ ํ…์ŠคํŠธ, ์ •๋ ฌ์„ ์„ค์ •ํ•ด ์ฃผ๊ณ , ๋งˆ์ง€๋ง‰์— titleView๋กœ ์„ธํŒ…์„ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

 

Editing ๋ชจ๋“œ์—์„œ ์š”์†Œ ์‚ญ์ œํ•˜๊ธฐ / ์š”์†Œ ์ด๋™ํ•˜๊ธฐ

Editing ๋ชจ๋“œ๋Š” tableView์—์„œ ์„ค์ •์ด ๋˜๋Š” ์š”์†Œ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ €๋ฒˆ ์‹œ๊ฐ„์— ์ƒ์„ฑํ•ด ๋‘” ๋ณธ ํด๋ž˜์Šค์™€ ๊ตฌ๋ถ„ํ•˜์—ฌ UITableViewDataSource์™€ UITableViewDelegate ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ ํ™•์žฅ ํด๋ž˜์Šค์— ๊ตฌํ˜„์„ ํ•ด ์ค„ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

 

extension ViewController: UITableViewDataSource, UITableViewDelegate {
   
    // editing ๋ชจ๋“œ์˜ ์Šคํƒ€์ผ
    func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
        return .delete
    }
    
    // editing ๋ชจ๋“œ์—์„œ์˜ ์š”์†Œ ์‚ญ์ œ
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == UITableViewCell.EditingStyle.delete {
            print("delete")
            self.dataManager.deleteTodoListData(indexPath.row)
            self.tableview.reloadData()
        }
    }
    
    // editing ๋ชจ๋“œ์—์„œ์˜ row ์ด๋™๊ตฌํ˜„
    func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
        let todolistArray = dataManager.getTodoListData()
        let targetList: TodoData = todolistArray[sourceIndexPath.row]
        dataManager.deleteTodoListData(sourceIndexPath.row)
        dataManager.insertTodoListData(destinationIndexPath.row, targetList)
    }
    
}

 

์šฐ์„  ์š”์†Œ์˜ ์‚ญ์ œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด editing Style ์— delete ๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ์‹œ๊ณ , commit editingStyle์ด ํฌํ•จ๋œ ํ•จ์ˆ˜์—์„œ ์‚ญ์ œํ•˜๋Š” ์š”์†Œ๋ฅผ ๊ตฌํ˜„ํ•ด ์ค๋‹ˆ๋‹ค. ๋ฐฐ์—ด์—์„œ ํ•ด๋‹น ์š”์†Œ๋ฅผ ์‚ญ์ œํ•  ๋•Œ๋Š” ์œ„์—์„œ ์ƒ์„ฑํ•œ ๋ฐฐ์—ด ์‚ญ์ œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ row์˜ ์ด๋™์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ด๋™์‹œํ‚ฌ ๋ฐฐ์—ด์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฅธ ๊ณณ์— ์ €์žฅํ•ด ๋‘” ๋’ค ํ•ด๋‹น ๋ฐฐ์—ด์„ ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฐฐ์—ด์—์„œ ์‚ญ์ œํ•ด ์ฃผ๊ณ , ์˜ฎ๊ธด ๊ณณ์— ๋ฐฐ์—ด์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋•Œ๋„ ๋˜ํ•œ ์œ„์—์„œ ๊ตฌํ˜„ํ•œ deleteํ•จ์ˆ˜์™€ insertํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.  

 

    • func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {}
      : tableView์˜ ํŽธ์ง‘๋ชจ๋“œ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜

    • func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {}
      : tableView์˜ ์‚ฝ์ž…๊ณผ ์‚ญ์ œ๋ฅผ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜
    • func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {}
      : tableView์˜ cell์„ ํŠน์ •์œ„์น˜๋กœ ์ด๋™์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜

 

 

์‹œ์—ฐ ์˜์ƒ

 

 

 

 

์ƒˆ๋กœ์šด ๊ตฌํ˜„๋„ ๋งŽ์ด ํ•ด๋ณด๊ณ , ๋งŒ๋“œ๋Š” ๋Œ€๋กœ ์™์™ ๋งŒ๋“ค์–ด์ ธ์„œ ์•„์ฃผ ์ฆ๊ฑฐ์› ๋˜ ํ•˜๋ฃจ์˜€์–ด์š”.

์ฒ˜์Œ์—” ์ทจ์†Œ์„  ๊ตฌํ˜„์ด ํž˜๋“ค์–ด์„œ ์ฉ”์ฉ”๋งค๋‹ค๊ฐ€ NSAttributedString๋ถ€ํ„ฐ ๋‹ค์‹œ ๊ณต๋ถ€๋ฅผ ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋” ์ž์„ธํ•˜๊ฒŒ ๊ณต๋ถ€ํ•˜์—ฌ ๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ ์—…๋กœ๋“œํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.ใ…Ž