Как правильно делать верстку для приложения?


#1

Доброго времени всем.
Появился такой вопрос, у меня есть допустим одинаковые UILabel в проекте, и я хочу сделать один общий класс для UILabel и потом наследовать его другими.
Правильный ли это подход?
Просто никогда не видел чтобы кто то создавал отдельный класс для каждого элемента и задавал ему шрифт и размер, в основном всё делают в IB.


#2

Все правильно вы думаете. Так делают и это правильно.
Это очень нужно для создания своих стилей каждому элементу. В будущем таким образом менять или править что-то проще в одном своем классе.


#3

То есть условно говоря мне нужно делать так.
Создать класс от UILabel.

class customLabel : UILabel {
// тут код
}

Потом в IB унаследовать этот класс?


#4

Именно так…
Для большей гибкости, можно создать для каждого элемента общий класс, с общими настройками
class StyledLabel: UILabel {}
В нем можно делать общие настройки для всех лейблов.
Дальше можно уже создавать конкретные классыы под каждый стиль

class BodyPrimaryLabel: StyledLabel {
    // тут указывать уже конкретные стили, фонт, цвет, фон и т.д.
}
class BodySecondaryLabel: StyledLabel {
    // тут указывать уже конкретные стили, фонт, цвет, фон и т.д.
}

И так далее. Для любого элемента.
Так же советую вынести отдельно цвета, размер текста. Из этого скомпоновать фонт. Т.е. у вас получится полноценный конструктор.
В конце вам нужно будет лишь указать для элемента нужный класс и задать текст.
Все изменения будут в одном месте. Понадобилось для Primary стиля увеличить размер текста, легко. Поменять цвет текста для заголовков, легко.


#5

Спасибо вам большое!


#6

А не проще сделать стиль и скармливать его как зависимость, зачем столько наследников?

вот что я имею ввиду

protocol TextStyleType {
    var font: UIFont { get }
    var textColor: UIColor { get }
    var textAlignment: NSTextAlignment { get }
}

protocol TextStyleApplicable {
    func applyStyle(_ style: TextStyleType)
}

extension UILabel: TextStyleApplicable {
    func applyStyle(_ style: TextStyleType) {
        self.font = font
        self.textColor = style.textColor
        self.textAlignment = style.textAlignment
    }
}

extension UITextField: TextStyleApplicable {
    func applyStyle(_ style: TextStyleType) {
        self.font = font
        self.textColor = style.textColor
        self.textAlignment = style.textAlignment
    }
}

extension UITextView: TextStyleApplicable {
    func applyStyle(_ style: TextStyleType) {
        self.font = font
        self.textColor = style.textColor
        self.textAlignment = style.textAlignment
    }
}

struct ConcreteTextStyle: TextStyleType {
    var font: UIFont
    var textColor: UIColor
    var textAlignment: NSTextAlignment
}


enum TextStyleFactory {
    // MARK: - Main header style
    static let mainHeaderTextStyle = ConcreteTextStyle(
        font: .systemFont(ofSize: 30),
        textColor: .blue,
        textAlignment: .center
    )
    static let mainHeaderTextStyleLeft = mainHeaderTextStyle.byAdding(.textAlignment(.left))
    
    // MARK: - Message text style
    static let messageTextStyle = ConcreteTextStyle(
        font: .systemFont(ofSize: 18),
        textColor: .blue,
        textAlignment: .center
    )
    static let messageTextStyleLeft = messageTextStyle.byAdding(.textAlignment(.left))
    static let messageTextStyleRight = messageTextStyle.byAdding(.textAlignment(.right))
}
    

let field = UITextField()
let label = UITextField()
let textView = UITextField()

field.applyStyle(TextStyleFactory.mainHeaderTextStyle)
label.applyStyle(TextStyleFactory.messageTextStyle)
textView.applyStyle(TextStyleFactory.messageTextStyleLeft)

#7

На самом деле все так и есть, в простом варианте. Хотя у вас вышло чересчур сложно.
Но если нужно делать более гибкую систему стилей, с поддержкой разных фич, там уже будет кода и логики больше. Как говорится “на вкус и цвет…”.
Я делал кастомные классы под каждый элемент вью, а уже от них создавал конкретные классы со стилями. Это мне показалось логичным. Так я мог в базовом классе делать определенные манипуляции со стилями, если нужно было. Так же создавал различные модификаторы и прочее.
Позже напарник решил сделать свою версию стилей и он отказался от кастомных классов. У него было похожее на ваш случай. Каждый разработчик хочет сделать по своему, что бы было проще(на его взгляд), но кому-то это будет казаться не таким простым. Поэтому от сюда и возникает множество решений, изучив которые, можно принять заключение и использовать то что нравится, либо пробовать сделать по своему, что покажется проще. Замкнутый круг :slight_smile:


#8

Добрый день уважаемые форумчане! Что бы разобраться в этом вопросе необходимо вспомнить какой язык понимает процессор вашего телефона. Он понимает язык машинных кодов. Первоначально писали на них. Потом создавались языки программирования все более и более высоких уровней. И наконец появился SWIFT! Встает вопрос, а почему обобщение которое мы обсуждаем не предусмотрено в компиляторе? Ответ по моему очевиден. Это сделало SWIFT менее гибким и более сложным. Т.е. в компиляторе предусмотрена золотая середина обобщенности языка. Далее вопрос: " А если в моем приложении можно сделать более высокий уровень обобщенности, то мне это делать?" Ответ да делать, но только в вашем приложении. В других это может мешать.