[iOS]Tự tạo bàn phím support chửi bậy trong Liên Quân Mobile
TL;DR Vậy là 1 mùa phượng đỏ nữa lại đến, mang theo trong mình hơi thở nồng ấm của mùa hè. Mùa hè là mùa của sự bùng cháy, phát triển mãnh liệt. Cũng là mùa mà các em nhỏ xa thầy cô, xa bạn bè xa mái trường yêu dấu, ngày đêm quên ăn quên ngủ phá rank mùa hè. Trong bất cứ game đấu nào, bạn ...
TL;DR
Vậy là 1 mùa phượng đỏ nữa lại đến, mang theo trong mình hơi thở nồng ấm của mùa hè. Mùa hè là mùa của sự bùng cháy, phát triển mãnh liệt. Cũng là mùa mà các em nhỏ xa thầy cô, xa bạn bè xa mái trường yêu dấu, ngày đêm quên ăn quên ngủ phá rank mùa hè.
Trong bất cứ game đấu nào, bạn cũng có thể bắt gặp các em nhỏ miệt mài cống hiến cho nền e-sport nước nhà
- Rừng gank team
- Óc ch*
- Thích ra solo
- Team như l**
Thỉnh thoảng cũng có 1 vài anh hùng ngã xuống vì bị mẹ gank. Các đồng đội khác lại ân cần hỏi han "Đ* con ch- lại afk"
Nhưng trong lúc chơi game, không thể chat 1 dòng text dài như vậy được. Màn hình của bạn sẽ lập tức dổi màu xám (nhân vật chết)
Để đáp ứng nhu cầu động viên nhanh, ra yêu cầu 1 cách lịch sự của các em sửa nhi, chúng ta cùng vận dụng 1 tí kiến thức đơn giản về iOS để làm 1 cái bàn phím dành riêng cho các em nhỏ
Bàn phím sẽ phục vụ việc xả stress mà vẫn đảm bảo một môi trường e-sport lành mạnh
Lên ý tưởng
Để thực hiện nhu cầu trên, bạn cần 1 cái bàn phím custom, với 1 số ít các button.
Khi bấm vào các button trên, keyboard của bạn sẽ tự động sinh ra các dòng text mang ý nghĩa nhân văn cao đẹp
Chuẩn bị giao diện, nội dung text
Giao diện bàn phím sẽ như thế này
Text hiển thị trên bàn phím
DCMM | Óc cờ hó | Team lol | Solo | Tuổi lol Jungle | AP | AD | Top | Gank Cố thủ | Đẩy lẻ | Tập trung | Farm | Đẩy trụ Ăn KK | Bỏ KK | All Mid | Win luôn | Đầu hàng
Text thực tế sẽ output ra
Tôi muốn đưa mẫu hậu của đồng chí lên đỉnh | Đồng chí thật sáng dạ | Thật tuyệt khi được sát cánh cùng các đồng chí | T muốn so tài cùng đồng chí | Trình độ của đồng chí thật muốn t đâm vào T sẽ làm rừng gank team | Mid cứ tin ở t | T làm AD nhé | T đi đường KK | Làm ơn giúp mình Cố thủ, đừng feed | Thủ nhà để t đẩy lẻ | Tập trung chuẩn bị vào | Farm đi, đợi late | Đẩy trụ đi", Ăn KingKong luôn | Không ổn, bỏ KK đi | All Mid | Win luôn | Mãi là anh em nhé, trận sau gặp lại
Start
Bạn có thể đọc thêm về Custom Keyboard ở đây
https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/CustomKeyboard.html
Tạo 1 project với tên tùy thích theo ý bạn.
Tại project đã tạo, add CustomKeyboardExtension bằng cách
File > New > Target > CustomKeyboardExtension
Bạn sẽ thấy có 1 thư mục mới được thêm vào trong project
**Note : ** đừng quên chuyển Deployment Target của Extension sang cùng Deployment Target của app nhé
Run app
Lần đầu tiên chạy app, bạn sẽ không thấy keyboard mới của bạn đâu. Hãy vào setting để add nó
Settings > General > Keyboard > Add New Keyboard
KeyboardViewController
Đây là controller quản lý keyboard của bạn.
- self.inputView -> chính là phần keyboard view mặc định
- self.textDocumentProxy
Bạn không thể trực tiếp thao tác với editor (textfield, textview ...) mà phải thực hiện việc đó thông qua textDocumentProxy
Khởi tạo giao diện bàn phím
Một bàn phím sẽ nên có các thành phần
- Next keyboard button
- Space
- Delete button
- Các button khác
** Khởi tạo các phím chức năng**
Để tiện cho việc khởi tạo giao diện bàn phím, bạn có thể tạo view qua file .xib cho dễ hình dung
File > New > File > View
Đừng quên check vào Target KeyboardExtension
Bạn có thể set height của nó thành 216 cho tương đồng với kích thước của các bàn phím khác. Kéo thả các button chức năng
Khởi tạo text button
Bàn phím của chúng ta sẽ có 4x5 button -> chúng ta sẽ dùng code để khởi tạo chúng (hoặc bạn có thể kéo thả 20 cái button tùy theo sở thích)
Ở đây, tôi sẽ sử dụng SnapKit để support việc tạo autolayout cho các button.
let numRow = 4 let numColumn = 5 let space: CGFloat = 6.0 let lineSpace: CGFloat = 10.0 let texts = [ "DCMM", "Óc cờ hó", "Team lol", "Solo", "Tuổi lol", "Jungle", "AP", "AD", "Top", "Gank", "Cố thủ", "Đẩy lẻ", "Tập trung", "Farm", "Đẩy trụ", "Ăn KK", "Bỏ KK", "All Mid", "Win luôn", "Đầu hàng" ] let displayTexts = [ "Tôi muốn đưa mẫu hậu của đồng chí lên đỉnh", "Đồng chí thật sáng dạ", "Thật tuyệt khi được sát cánh cùng các đồng chí", "T muốn so tài cùng đồng chí", "Trình độ của đồng chí thật muốn t đâm vào", "T sẽ làm rừng gank team", "Mid cứ tin ở t", "T làm AD nhé", "T đi đường KK", "Làm ơn giúp mình", "Cố thủ, đừng feed", "Thủ nhà để t đẩy lẻ", "Tập trung chuẩn bị vào", "Farm đi, đợi late", "Đẩy trụ đi", "Ăn KingKong luôn", "Không ổn, bỏ KK đi", "All Mid", "Win luôn", "Mãi là anh em nhé, trận sau gặp lại" ] private func setupButtons() { // 1 var indexColumnButton: ShapeButton? var indexRowButton: ShapeButton? // 2 let awidthOffset = space * CGFloat(numColumn + 1) / CGFloat(numColumn) let heightOffset = (lineSpace * CGFloat(numRow + 1) + 50) / CGFloat(numRow) // 3 for i in 0..<numRow { for j in 0..<numColumn { let button = ShapeButton(type: .system) button.tag = (i * numColumn + j) button.setTitle(texts[button.tag], for: .normal) button.addTarget(self, action: #selector(didSelectTextButton(btn:)), for: .touchDown) self.addSubview(button) button.snp.makeConstraints { (maker) in maker.awidth.equalTo(self.snp.awidth).dividedBy(numColumn).offset(-awidthOffset) maker.height.equalTo(self).dividedBy(numRow).offset(-heightOffset) if let lastButton = indexColumnButton { maker.leading.equalTo(lastButton.snp.trailing).offset(space) maker.top.equalTo(lastButton.snp.top) } else { if let lastRow = indexRowButton { maker.top.equalTo(lastRow.snp.bottom).offset(lineSpace) } else { maker.top.equalTo(self).offset(lineSpace) } maker.leading.equalTo(self).offset(space) } } indexColumnButton = button if j == 0 { indexRowButton = button } } indexColumnButton = nil } } private func commonInit() { setupButtons() }
Đoạn code trên có thể hiểu như sau
- Có tổng cộng 4x5 ShapeButton (custom of UIButton class, bạn có thể dùng UIButton)
- Set property, tag + target cho button
- Mỗi button sẽ được set layoutconstraint như sau:
- Tất cả các button có size bằng nhau
- Khoảng cách giữa button với button trước nó = 6
- Khoảng cách giữa button với button trên nó = 10
- Các button ở biên (trên dưới trái phải) sẽ cách biên = 6
Nếu bạn không dùng autolayout mà sử dụng frame thì nhớ set lại frame mỗi khi layoutSubview được gọi nhé
Add keyboard view
Sau khi đã khởi tạo xong custom keyboard view, chúng ta sẽ add nó vào KeyboardViewController
var leKeyboard: LeKeyboardView! override func viewDidLoad() { super.viewDidLoad() guard let inputView = self.inputView else { return } let view = LeKeyboardView(frame: inputView.bounds) self.leKeyboard = view inputView.addSubview(self.leKeyboard) leKeyboard.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ leKeyboard.leftAnchor.constraint(equalTo: inputView.leftAnchor), leKeyboard.topAnchor.constraint(equalTo: inputView.topAnchor), leKeyboard.rightAnchor.constraint(equalTo: inputView.rightAnchor), leKeyboard.bottomAnchor.constraint(equalTo: inputView.bottomAnchor) ]) }
Chạy ứng dụng để check Keyboard
Add action cho Keyboard
Next Keyboard Button
Đây là 1 button đặc biệt, hãy để KeyboardViewController xử lý nó
leKeyboard.nextKeyboardButton.addTarget( self, action: #selector(handleInputModeList(from:with:)), for: .allTouchEvents)
iOS sẽ tự động xử lý nó như nextKeyboardButton ở các keyboard mặc định
- Tap to next
- Hold to select
Delete Button
Ở KeyboardView.swift, chúng ta sẽ add action cho delete button, và trả sự kiện qua closure
var didTapDelete: (() -> Void)? func commonInit { self.deleteButton.addTarget(self, action: #selector(didTapDeleteButton(_:)), for: .touchDown ) } @IBAction private func didTapDeleteButton(_ sender: Any) { didTapDelete?() }
và xử lý tại KeyboardViewController
leKeyboard.didTapDelete = { [weak self] in let proxy = self?.textDocumentProxy if let lastText = proxy?.documentContextBeforeInput?.components(separatedBy: " ").last { if lastText.isEmpty { proxy?.deleteBackward() return } for _ in 0..<lastText.count { proxy?.deleteBackward() } } else { proxy?.deleteBackward() } }
textDocumentProxy.deleteBackward chỉ delete 1 ký tự, chúng ta có thể sửa lại để nó delete 1 từ
Text Button và Space button Tương tự như Delete Button, chúng ta cũng add target cho các button (tại nơi khởi tạo ở vòng for)
button.addTarget(self, action: #selector(didSelectTextButton(btn:)), for: .touchDown)
var didTapButton: ((String) -> Void)? @IBAction private func didSelectTextButton(btn: UIButton) { let text = displayTexts[btn.tag] didTapButton?(text) }
và xử lý tại KeyboardViewController
leKeyboard.didTapButton = { [weak self] text in self?.textDocumentProxy.insertText(text) }
Run app và nhận kết quả
Một số custom khác
Porn lover
Bạn có thể đổi text để tạo ra 1 bàn phím dành riêng cho việc học tập
let texts = [ "Porn1", "Porn2" ... ] let displayTexts = [ "www.porn1.com", "www.porn2.com" ... ]
Porn love random
bàn phím chỉ có 1 button, và bạn có thể random chọn 1 trong số các site trong list trên để truyền text
Daily Report =))
Gửi lời chúc
Tự nhắn đê cho ý nghĩa ...
Resource
Ứng dụng được làm dựa trên ý tưởng bàn phím riêng của box iMessage
Download Here