-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#20] HandySearchBar 추가 #34
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
searchBar를 사용하는 입장에서 leftButton에 액션을 지정할 때 leftButton.addTarget하는 방식이 조금 어색해보이는 것 같아요. 애플 기본 컴포넌트 중 contextMenu 같은 것들은 delegate 등의 방식으로 지정할 수 있어요.
물론 button에 addTarget하는 것은 더 많은 것을 커스터마이징할 수 있겠지만 아마 터치 이벤트 말고는 사용하는 일이 없을 것 같아요. 따라서 좀 더 사용하기 편하게 해주시면 좋을 것 같아요!!
textField 관련해서도 사용하기 좀 더 편하게 delegate나 프로퍼티 등을 제공할 수 있을 것 같아요. 만약 text input이 비어있을 때 rightButton을 비활성화 하고 싶다면 어떻게 로직을 작성할 수 있을까요?
-> 현재 textField가 private이기 때문에 addTarget, notification, delegate 모두 불가능할 것 같아요..ㅠ override 하는 선택지도 final이기 때문에 안될 것 같구요.
이 컴포넌트를 사용하여 검색 기능을 구현한다고 했을 때, 사용자가 입력한 내용은 어떻게 받아올 수 있나요? public 이상의 접근으로 활성된 text같은 프로퍼티나 delegate 등을 뚫어놓으면 더 좋을 것 같아요!!
@Invalidating(wrappedValue: true, .layout) public var leftIcon: Bool { | ||
didSet { | ||
leftButton.isHidden = !leftIcon | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
layout을 무효화(Invalidating) 시키면 setNeedsLayout()가 불리게 됩니다. (출처)
setNeedsLayout()은 다음 UI 업데이트 사이클에 layoutSubviews() 함수를 부르게 해줍니다.
그래서, @invalidating(.layout) 에 따라서 다시 subview들을 배치해야 하는 상황일 때 추가적인 작업은 layoutSubviews() 을 오버라이딩 해서 넣는거죠.
여기에서는 @Invalidating
과 didSet
중 하나는 굳이 필요하지 않을 것 같아요. @Invalidating
을 사용한다면 didSet보다는 layoutSubviews() 함수를 오버라이딩해서 leftButton과 rightButton의 hidden을 결정하면 될 것 같구요, didSet을 사용한다면 @Invalidating
방식은 아예 사용하지 않는 편이 좋을 것 같아요.
더 편한 방식을 고민해서 사용해주시면 될 것 같습니다~!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HandySearchBarViewController 부분 (디버깅하는 뷰)에 아무 버튼을 하나 만들고 searchBar1.leftIcon.toggle()
을 해보시면 잘 동작하는지 확인할 수 있어요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
흠 말씀해주신 내용을 바탕으로 다시 고민해보니, invalidating 접근은 레이아웃을 전반적으로 수정해야 하는 경우에 적합하지만, 버튼의 hidden 속성과 같이 간단한 UI 요소 변경에는 과도할 것 같다는 생각이 드네요!
버튼과 텍스트 필드의 레이아웃도 스택뷰로 관리하고 있으니 굳이 무효화가 필요없기 때문에 간단히 didset으로 변경해도 충분할것 같습니다!
didset으로 변경하는 방향으로 수정하겟습니다~! 좋은 답변 감사드립니다!
import UIKit | ||
import SnapKit | ||
|
||
final public class HandySearchBar: UIView { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 컴포넌트를 final로 규정짓는 것은 살짝 위험할 수도 있다고 생각해요!
HandySearchBar를 상속받아서 더 꾸밀 수도 있다고 생각하기 때문에 final public보다는 필요한 곳에 open 접근제어를 걸어두는 것도 좋다고 생각합니다~!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗 맞습니다. 추가적인 커스텀이 필요한 상황이 분명 발생할거기 때문에 final은 과하다라는 생각이 듭니다. 필요한 부분에 open으로 수정했습니다!
변수명은 말씀해주신대로 변경이 필요해보이네요. 사용하는 입장에서 매우 혼동될 것 같아요. |
버튼과 텍스트 필드가 공존하면서 버튼의 역할이 정해지지 않은 컴포넌트는 흔하지 않아서 어떻게 버튼 이벤트를 처리해야할지 고민했는데, 처음에 addTarget을 사용했던 이유는 직관성 때문이었습니다. 예를 들어 오른쪽 버튼인 필터 버튼을 터치가 아닌 꾹 눌렀을때 필터 옵션이 나오는 기획이라면 버튼이 터치 이외의 용도가 바뀌는 상황이 생기기도 하고 또는 버튼이 아예 없는 상황도 존재하기 때문에 addTarget이 더 직관적이고 조금이라도 문서를 덜보고 활용할수 있을것 같다는 개인적인 생각을 했습니다. 컴포넌트의 핵심인 재사용성을 생각하면 delgate로 자주쓰이는 상황(터치 이벤트)를 정의하고 외부에서 바로 사용할수 있게 하는것이 더 편리할것 같습니다. 한편으로는 delegate가 조금은 과하다는 생각이 들기도 하는데 클로저로 전달하는 방식은 또 자주 사용하는 방식은 아니라서 고민입니다 ㅠ @LeeJoEun-01 은 어떻게 생각하시나욥?
uikit의 텍스트 필드에는 여러개의 델리게이트가 있는데 이중에서 자주 사용하는건 한정적이고 handy에서 모든상황을 가정하고 delegate를 만드는것 보다 외부에서 override를 사용하는게 더 괜찮을것 같다는 생각이 듭니다! 일반 텍스트 필드라면 여러 델리게이트가 도움이 될수 있지만 텍스트 필드중에서 searchBar의 성격을 띈다면 더 줄어 들것 같아요. 그래서 차라리 textField를 public으로 열어두는게 좋을지 일부 필요한 델리게이트만 고민해서 넣을지 조금만 더 고민해서 반영하겠습니다!
이부분을 미쳐 생각하지 못했습니다 ㅠ 말씀해주신대로 textField의 text를 리턴해주는 text 프로퍼티를 만들어 두었습니다! /**
텍스트 필드의 입력 값을 외부에서 가져올 수 있는 프로퍼티입니다.
*/
open var text: String? {
return textField.text
} 위와같이 open으로 text 뚫어두었습니당 |
흐음 저도 평소에 버튼에 이벤트를 추가할 때 사용하는 AddTarget이 더 직관적이라고 생각해요! 물론 delegate도 양방향으로 무언가를 전달하는 대리자 역할을 하는건 맞지만 평소에 버튼을 추가할때 사용하는 방법인 AddTarget을 사용하는게 나중에 사용하는 사람들에게 더 직관적으로 와닿지 않을까요?? @hye0njuoo @chongin12 |
구현중에 고민인 부분이 생겼는데요. @objc public protocol HandySearchBarDelegate: NSObjectProtocol {
/**
텍스트 필드가 편집을 시작할 때 호출됩니다.
*/
@objc optional func handySearchBarDidBeginEditing(_ searchBar: HandySearchBar)
/**
텍스트 필드가 편집을 종료할 때 호출됩니다.
*/
@objc optional func handySearchBarDidEndEditing(_ searchBar: HandySearchBar)
} 이 방법과 public protocol HandySearchBarDelegate: AnyObject {
// 텍스트 필드가 편집을 시작할 때 호출됩니다.
func handySearchBarDidBeginEditing(_ searchBar: HandySearchBar)
// 텍스트 필드가 편집을 종료할 때 호출됩니다.
func handySearchBarDidEndEditing(_ searchBar: HandySearchBar)
}
public extension HandySearchBarDelegate {
// 기본 구현 제공 (선택적 구현)
func handySearchBarDidBeginEditing(_ searchBar: HandySearchBar) {
// 기본 구현 (빈 함수)
}
func handySearchBarDidEndEditing(_ searchBar: HandySearchBar) {
// 기본 구현 (빈 함수)
}
} 이렇게 프로토콜의 extenstion으로 하는 방법이 있던데 어떤방법이 좋을까요? 아니면 그냥 구현하도록 강제하는건 별로인가요 ㅎㅎ? |
isLeftButtonHidden, isRightButtonHidden 변수명으로 수정했습니다. figma와 다른 이름은 문서 작성시 따로 명시해 혼란 없도록 해두겠습니다! |
둘 다 일리있는 접근인 것 같아요! 모두 optional 함수라면 extension쪽이 더 일리가 있다고 생각합니다!! 둘 중 편하신 것으로 하시면 될 것 같아요~! |
📌 Summary
handySearchBar 컴포넌트를 추가했습니다.
✍️ Description
💡 PR Point
- clearButton
기본 clearButton이 아닌 handyIcon이 적용된 clearButton을 사용하기 위해 clearButton을 따로 구현했습니다.
텍스트 입력 감지:
textField에 입력이 발생할 때마다 textDidChange() 메서드가 호출됩니다.
이 메서드는 textField.text?.isEmpty 값을 확인하여 텍스트 필드가 비어 있으면 clearButton을 숨기고, 비어 있지 않으면 버튼을 표시합니다
클릭 동작:
사용자가 clearButton을 클릭하면 clearText() 메서드가 호출되어 텍스트 필드 글자를 지워줍니다.
이 메서드는 텍스트 필드의 내용을 지우고 (textField.text = ""), 다시 clearButton을 숨겨줍니다. (clearButton.isHidden = true).
- left,right 버튼 public
외부에서 이 컴포넌트를 사용할때 각 버튼에 기능을 연결하기 위해 public으로 접근할수 있도록 했습니다. 외부에서 연결할수 있도록 함수를 따로 빼두어 캡슐화를 더 견고히 할지, 지금처럼 그냥 public으로 열어둘지 고민입니다.
- 변수명 고민
현재 왼쪽 버튼, 오른쪽 버튼 여부를 피그마 properties 이름인 leftIcon,rightIcon이라는 이름으로 관리하고 있는데, 외부에서 사용할때 좋은 변수명은 아닌것 같습니다.
isLeftButtonVisible, isLeftButtunAble 이름으로 바꾸면 어떨까요?
📚 Reference
https://developer.apple.com/documentation/uikit/uitextfield/viewmode
🔥 Test
Simulator.Screen.Recording.-.iPhone.16.Pro.-.2025-01-03.at.23.49.04.mp4