Вступление
Всем привет, меня зовут Григорий, последние 5 лет занимался программированием под iOS. Сейчас решил сменить сферу деятельности и ударился в веб, но чтобы добро не пропадало, хочу поделиться с сообществом своими наработками, накопившимися за это время. Библиотеки выложены на GitHub и добавлены в CocoaPods. Инструкции по установке и использованию вы сможете найти по ссылкам на GitHub, здесь же будет краткое описание.
Минимальная поддерживаемая версия — iOS 6.0.
LGAlertView
UIAlertView — один из часто используемых компонентов при разработке на iOS. Выглядит и работает из коробки замечательно, проблема в том, что возможностей кастомизировать его Apple практически не дает, есть только несколько стандартно заданных стилей отображения. А что если нам нужно вставить внутрь свою вьюху, или банально поменять цвет кнопок или фона? Вот и было принято решение написать универсальный класс, который повторял бы работу UIAlertView, но имел широкие возможности по настройке. Так и появился LGAlertView.
При инициализации у нас есть возможность выбора между несколькими стилями:
- (instancetype)initWithTitle:(NSString *)title
message:(NSString *)message
buttonTitles:(NSArray *)buttonTitles
cancelButtonTitle:(NSString *)cancelButtonTitle
destructiveButtonTitle:(NSString *)destructiveButtonTitle;
Cо встроенной вьюхой (заголовок + сообщение + UIView + кнопки):
- (instancetype)initWithViewStyleWithTitle:(NSString *)title
message:(NSString *)message
view:(UIView *)view
buttonTitles:(NSArray *)buttonTitles
cancelButtonTitle:(NSString *)cancelButtonTitle
destructiveButtonTitle:(NSString *)destructiveButtonTitle;
C индикатором активности (заголовок + сообщение + UIActivityIndicatorView + кнопки):
- (instancetype)initWithActivityIndicatorStyleWithTitle:(NSString *)title
message:(NSString *)message
buttonTitles:(NSArray *)buttonTitles
cancelButtonTitle:(NSString *)cancelButtonTitle
destructiveButtonTitle:(NSString *)destructiveButtonTitle;
C полосой прогресса (заголовок + сообщение + UIProgressView + кнопки):
- (instancetype)initWithActivityIndicatorStyleWithTitle:(NSString *)title
message:(NSString *)message
buttonTitles:(NSArray *)buttonTitles
cancelButtonTitle:(NSString *)cancelButtonTitle
destructiveButtonTitle:(NSString *)destructiveButtonTitle;
C полями ввода (заголовок + сообщение + поля ввода + кнопки):
- (instancetype)initWithActivityIndicatorStyleWithTitle:(NSString *)title
message:(NSString *)message
buttonTitles:(NSArray *)buttonTitles
cancelButtonTitle:(NSString *)cancelButtonTitle
destructiveButtonTitle:(NSString *)destructiveButtonTitle;
Для возможности отлавливать события есть несколько путей: делегирование, как в стандартном UIAlertView, и блоки (кому как больше нравится). Кроме того, предусмотрены NSNotification для появления и исчезновения LGAlertView с экрана. Сначала думал добавить нотификации и для кнопок, но решил, что все-таки это будет лишним.
@property (assign, nonatomic) id<LGAlertViewDelegate> delegate;
- (void)alertViewWillShow:(LGAlertView *)alertView;
- (void)alertViewWillDismiss:(LGAlertView *)alertView;
- (void)alertViewDidShow:(LGAlertView *)alertView;
- (void)alertViewDidDismiss:(LGAlertView *)alertView;
- (void)alertView:(LGAlertView *)alertView buttonPressedWithTitle:(NSString *)title index:(NSUInteger)index;
- (void)alertViewCancelled:(LGAlertView *)alertView;
- (void)alertViewDestructiveButtonPressed:(LGAlertView *)alertView;
Блоки:
@property (strong, nonatomic) void (^willShowHandler)(LGAlertView *alertView);
@property (strong, nonatomic) void (^willDismissHandler)(LGAlertView *alertView);
@property (strong, nonatomic) void (^didShowHandler)(LGAlertView *alertView);
@property (strong, nonatomic) void (^didDismissHandler)(LGAlertView *alertView);
@property (strong, nonatomic) void (^actionHandler)(LGAlertView *alertView, NSString *title, NSUInteger index);
@property (strong, nonatomic) void (^cancelHandler)(LGAlertView *alertView, BOOL onButton);
@property (strong, nonatomic) void (^destructiveHandler)(LGAlertView *alertView);
NSNotifications:
kLGAlertViewWillShowNotification;
kLGAlertViewWillDismissNotification;
kLGAlertViewDidShowNotification;
kLGAlertViewDidDismissNotification;
Для настройки внешнего вида есть много свойств. Перечислять их долго, думаю из названий должно быть все понятно:
/** Default is YES */
@property (assign, nonatomic, getter=isCancelOnTouch) BOOL cancelOnTouch;
/** Set highlighted buttons background color to blue, and set highlighted destructive button background color to red. Default is YES */
@property (assign, nonatomic, getter=isColorful) BOOL colorful;
@property (strong, nonatomic) UIColor *tintColor;
@property (strong, nonatomic) UIColor *coverColor;
@property (strong, nonatomic) UIColor *backgroundColor;
@property (assign, nonatomic) CGFloat layerCornerRadius;
@property (strong, nonatomic) UIColor *layerBorderColor;
@property (assign, nonatomic) CGFloat layerBorderWidth;
@property (strong, nonatomic) UIColor *layerShadowColor;
@property (assign, nonatomic) CGFloat layerShadowRadius;
@property (assign, nonatomic) CGFloat heightMax;
@property (assign, nonatomic) CGFloat widthMax;
@property (strong, nonatomic) UIColor *titleTextColor;
@property (assign, nonatomic) NSTextAlignment titleTextAlignment;
@property (strong, nonatomic) UIFont *titleFont;
@property (strong, nonatomic) UIColor *messageTextColor;
@property (assign, nonatomic) NSTextAlignment messageTextAlignment;
@property (strong, nonatomic) UIFont *messageFont;
@property (strong, nonatomic) UIColor *buttonsTitleColor;
@property (strong, nonatomic) UIColor *buttonsTitleColorHighlighted;
@property (assign, nonatomic) NSTextAlignment buttonsTextAlignment;
@property (strong, nonatomic) UIFont *buttonsFont;
@property (strong, nonatomic) UIColor *buttonsBackgroundColorHighlighted;
@property (assign, nonatomic) NSUInteger buttonsNumberOfLines;
@property (assign, nonatomic) NSLineBreakMode buttonsLineBreakMode;
@property (assign, nonatomic) BOOL buttonsAdjustsFontSizeToFitWidth;
@property (assign, nonatomic) CGFloat buttonsMinimumScaleFactor;
@property (strong, nonatomic) UIColor *cancelButtonTitleColor;
@property (strong, nonatomic) UIColor *cancelButtonTitleColorHighlighted;
@property (assign, nonatomic) NSTextAlignment cancelButtonTextAlignment;
@property (strong, nonatomic) UIFont *cancelButtonFont;
@property (strong, nonatomic) UIColor *cancelButtonBackgroundColorHighlighted;
@property (assign, nonatomic) NSUInteger cancelButtonNumberOfLines;
@property (assign, nonatomic) NSLineBreakMode cancelButtonLineBreakMode;
@property (assign, nonatomic) BOOL cancelButtonAdjustsFontSizeToFitWidth;
@property (assign, nonatomic) CGFloat cancelButtonMinimumScaleFactor;
@property (strong, nonatomic) UIColor *destructiveButtonTitleColor;
@property (strong, nonatomic) UIColor *destructiveButtonTitleColorHighlighted;
@property (assign, nonatomic) NSTextAlignment destructiveButtonTextAlignment;
@property (strong, nonatomic) UIFont *destructiveButtonFont;
@property (strong, nonatomic) UIColor *destructiveButtonBackgroundColorHighlighted;
@property (assign, nonatomic) NSUInteger destructiveButtonNumberOfLines;
@property (assign, nonatomic) NSLineBreakMode destructiveButtonLineBreakMode;
@property (assign, nonatomic) BOOL destructiveButtonAdjustsFontSizeToFitWidth;
@property (assign, nonatomic) CGFloat destructiveButtonMinimumScaleFactor;
@property (assign, nonatomic) UIActivityIndicatorViewStyle activityIndicatorViewStyle;
@property (strong, nonatomic) UIColor *activityIndicatorViewColor;
@property (strong, nonatomic) UIColor *progressViewProgressTintColor;
@property (strong, nonatomic) UIColor *progressViewTrackTintColor;
@property (strong, nonatomic) UIImage *progressViewProgressImage;
@property (strong, nonatomic) UIImage *progressViewTrackImage;
@property (strong, nonatomic) UIColor *progressLabelTextColor;
@property (assign, nonatomic) NSTextAlignment progressLabelTextAlignment;
@property (strong, nonatomic) UIFont *progressLabelFont;
@property (strong, nonatomic) UIColor *separatorsColor;
@property (assign, nonatomic) UIScrollViewIndicatorStyle indicatorStyle;
Чтобы показывать или скрывать LGAlertView предусмотрены следующие методы:
- (void)showAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)dismissAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
Кроме того удалось добиться правильного поведения в случае, когда появляется несколько вьюх подряд без закрытия предыдущих. Вы можете не боясь комбинировать UIAlertView, UIActionSheet, LGAlertView и LGActionSheet. При появлении новых старые будут исчезать, а при исчезновении — появляться.
LGActionSheet
Причины появления и принцип действия аналогичны LGAlertView.
Стили при инициализации:
- (instancetype)initWithTitle:(NSString *)title
buttonTitles:(NSArray *)buttonTitles
cancelButtonTitle:(NSString *)cancelButtonTitle
destructiveButtonTitle:(NSString *)destructiveButtonTitle;
Cо встроенной вьюхой (сообщение + UIView + кнопки):
- (instancetype)initWithTitle:(NSString *)title
view:(UIView *)view
buttonTitles:(NSArray *)buttonTitles
cancelButtonTitle:(NSString *)cancelButtonTitle
destructiveButtonTitle:(NSString *)destructiveButtonTitle;
События отлавливаются с помощью делегирования, блоков и нотификаций:
@property (assign, nonatomic) id<LGActionSheetDelegate> delegate;
- (void)actionSheetWillShow:(LGActionSheet *)actionSheet;
- (void)actionSheetWillDismiss:(LGActionSheet *)actionSheet;
- (void)actionSheetDidShow:(LGActionSheet *)actionSheet;
- (void)actionSheetDidDismiss:(LGActionSheet *)actionSheet;
- (void)actionSheet:(LGActionSheet *)actionSheet buttonPressedWithTitle:(NSString *)title index:(NSUInteger)index;
- (void)actionSheetCancelled:(LGActionSheet *)actionSheet;
- (void)actionSheetDestructiveButtonPressed:(LGActionSheet *)actionSheet;
Блоки:
@property (strong, nonatomic) void (^willShowHandler)(LGActionSheet *actionSheet);
@property (strong, nonatomic) void (^willDismissHandler)(LGActionSheet *actionSheet);
@property (strong, nonatomic) void (^didShowHandler)(LGActionSheet *actionSheet);
@property (strong, nonatomic) void (^didDismissHandler)(LGActionSheet *actionSheet);
@property (strong, nonatomic) void (^actionHandler)(LGActionSheet *actionSheet, NSString *title, NSUInteger index);
@property (strong, nonatomic) void (^cancelHandler)(LGActionSheet *actionSheet, BOOL onButton);
@property (strong, nonatomic) void (^destructiveHandler)(LGActionSheet *actionSheet);
NSNotifications:
kLGActionSheetWillShowNotification;
kLGActionSheetWillDismissNotification;
kLGActionSheetDidShowNotification;
kLGActionSheetDidDismissNotification;
Настройка внешнего вида и анимаций (по умолчанию анимации для iPhone и iPad различается):
@property (assign, nonatomic) LGActionSheetTransitionStyle transitionStyle;
/** Default is YES */
@property (assign, nonatomic, getter=isCancelOnTouch) BOOL cancelOnTouch;
/** Set highlighted buttons background color to blue, and set highlighted destructive button background color to red. Default is YES */
@property (assign, nonatomic, getter=isColorful) BOOL colorful;
@property (strong, nonatomic) UIColor *tintColor;
@property (strong, nonatomic) UIColor *coverColor;
@property (strong, nonatomic) UIColor *backgroundColor;
@property (assign, nonatomic) CGFloat layerCornerRadius;
@property (strong, nonatomic) UIColor *layerBorderColor;
@property (assign, nonatomic) CGFloat layerBorderWidth;
@property (strong, nonatomic) UIColor *layerShadowColor;
@property (assign, nonatomic) CGFloat layerShadowRadius;
@property (assign, nonatomic) CGFloat heightMax;
@property (assign, nonatomic) CGFloat widthMax;
@property (strong, nonatomic) UIColor *titleTextColor;
@property (assign, nonatomic) NSTextAlignment titleTextAlignment;
@property (strong, nonatomic) UIFont *titleFont;
@property (strong, nonatomic) UIColor *buttonsTitleColor;
@property (strong, nonatomic) UIColor *buttonsTitleColorHighlighted;
@property (assign, nonatomic) NSTextAlignment buttonsTextAlignment;
@property (strong, nonatomic) UIFont *buttonsFont;
@property (strong, nonatomic) UIColor *buttonsBackgroundColorHighlighted;
@property (assign, nonatomic) NSUInteger buttonsNumberOfLines;
@property (assign, nonatomic) NSLineBreakMode buttonsLineBreakMode;
@property (assign, nonatomic) BOOL buttonsAdjustsFontSizeToFitWidth;
@property (assign, nonatomic) CGFloat buttonsMinimumScaleFactor;
@property (strong, nonatomic) UIColor *cancelButtonTitleColor;
@property (strong, nonatomic) UIColor *cancelButtonTitleColorHighlighted;
@property (assign, nonatomic) NSTextAlignment cancelButtonTextAlignment;
@property (strong, nonatomic) UIFont *cancelButtonFont;
@property (strong, nonatomic) UIColor *cancelButtonBackgroundColorHighlighted;
@property (assign, nonatomic) NSUInteger cancelButtonNumberOfLines;
@property (assign, nonatomic) NSLineBreakMode cancelButtonLineBreakMode;
@property (assign, nonatomic) BOOL cancelButtonAdjustsFontSizeToFitWidth;
@property (assign, nonatomic) CGFloat cancelButtonMinimumScaleFactor;
@property (strong, nonatomic) UIColor *destructiveButtonTitleColor;
@property (strong, nonatomic) UIColor *destructiveButtonTitleColorHighlighted;
@property (assign, nonatomic) NSTextAlignment destructiveButtonTextAlignment;
@property (strong, nonatomic) UIFont *destructiveButtonFont;
@property (strong, nonatomic) UIColor *destructiveButtonBackgroundColorHighlighted;
@property (assign, nonatomic) NSUInteger destructiveButtonNumberOfLines;
@property (assign, nonatomic) NSLineBreakMode destructiveButtonLineBreakMode;
@property (assign, nonatomic) BOOL destructiveButtonAdjustsFontSizeToFitWidth;
@property (assign, nonatomic) CGFloat destructiveButtonMinimumScaleFactor;
@property (strong, nonatomic) UIColor *separatorsColor;
@property (assign, nonatomic) UIScrollViewIndicatorStyle indicatorStyle;
Чтобы показывать или скрывать LGActionSheet предусмотрены следующие методы:
- (void)showAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)dismissAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
LGSideMenuController
Без выезжающих боковых меню в наше время не обходится практически ни одно серьезное приложение. В какой-то момент надоело писать для каждого проекта разовые решения и была создана данная библиотека.
Краткий список возможностей:
- Поддерживается как левое меню, так и правое
- Различные виды анимаций
- Показ и скрытие по нажатию кнопки и по жесту
- Настройка правил показа для разных девайсов и ориентаций (например можно сделать меню нескрываемым для landscape ориентации на iPad)
- На выбор скрывать или показывать статус бар
- Широкие возможности по настройке внешнего вида
Добавить данный контроллер в проект довольно просто. Нужно указать ваш корневой контроллер (обычно это UINavigationController) как корневой контроллер LGSideMenuController'a… звучит немного тавтологично, приведу пример:
Обычная инициализация корневого контроллера в AppDelegate.m:
ViewController *viewController = [ViewController new];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
window.rootViewController = navigationController;
Инициализация с LGSideMenuController'ом:
ViewController *viewController = [ViewController new];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
LGSideMenuController *sideMenuController = [[LGSideMenuController alloc] initWithRootViewController:navigationController];
window.rootViewController = sideMenuController;
Настроить боковые меню тоже не сложно. Сначала необходимо включить те меню, которые вам нужны (левое, правое или обе):
[sideMenuController setLeftViewEnabledWithWidth:250.f // необходимая ширина области
presentationStyle:LGSideMenuPresentationStyleScaleFromBig // стиль анимации
alwaysVisibleOptions:0]; // правила показа
Далее добавьте свои вьюхи, которые будут показываться в боковом меню:
TableViewController *leftViewController = [TableViewController new];
[sideMenuController.leftView addSubview:leftViewController.tableView];
Чтобы показывать или скрывать боковые меню предусмотрены следующие методы:
- (void)showLeftViewAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)hideLeftViewAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)showHideLeftViewAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)showRightViewAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)hideRightViewAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)showHideRightViewAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
Также присутствуют следующие NSNotifications:
kLGSideMenuControllerWillShowLeftViewNotification;
kLGSideMenuControllerWillDismissLeftViewNotification;
kLGSideMenuControllerDidShowLeftViewNotification;
kLGSideMenuControllerDidDismissLeftViewNotification;
kLGSideMenuControllerWillShowRightViewNotification;
kLGSideMenuControllerWillDismissRightViewNotification;
kLGSideMenuControllerDidShowRightViewNotification;
kLGSideMenuControllerDidDismissRightViewNotification;
LGPlusButtonsView
Google последнее время активно продвигает свой Material Design, одним из компонентов которого является кнопка "+", вызывающая какие-либо дополнительные опции. Решение довольно интересное. На моей практике был заказчик, который просил подобный функционал реализовать на iOS. Поэтому тянуть резину не стал и сразу решил написать универсальное решение.
Краткий список возможностей:
- Можно добавить на любую вьюху
- Если добавлено на UIScrollView то при скролле будет скрываться
- Различные анимации появления кнопок
- Можно выводить в любом из углов
- Широкие возможности по настройке внешнего вида
Инициализация:
- (instancetype)initWithView:(UIView *)view
numberOfButtons:(NSUInteger)numberOfButtons
showsPlusButton:(BOOL)showsPlusButton;
События отлавливаются с помощью делегирования или блоков:
@property (assign, nonatomic) id<LGPlusButtonsViewDelegate> delegate;
- (void)plusButtonsView:(LGPlusButtonsView *)plusButtonsView buttonPressedWithTitle:(NSString *)title description:(NSString *)description index:(NSUInteger)index;
- (void)plusButtonsViewPlusButtonPressed:(LGPlusButtonsView *)plusButtonsView;
Блоки:
@property (strong, nonatomic) void (^actionHandler)(LGPlusButtonsView *plusButtonView, NSString *title, NSString *description, NSUInteger index);
@property (strong, nonatomic) void (^plusButtonActionHandler)(LGPlusButtonsView *plusButtonView);
Настройка внешнего вида и анимаций:
@property (assign, nonatomic, getter=isShowWhenScrolling) BOOL showWhenScrolling;
@property (strong, nonatomic) LGPlusButton *plusButton;
/** First is plusButton */
@property (strong, nonatomic) NSMutableArray *buttons;
/** First is plusButton description */
@property (strong, nonatomic) NSMutableArray *descriptions;
@property (assign, nonatomic) UIEdgeInsets contentInset;
@property (assign, nonatomic) UIEdgeInsets buttonInset;
@property (assign, nonatomic) CGSize buttonsSize;
@property (assign, nonatomic) CGSize plusButtonSize;
/** Description horizontal offset from button, default is 6.f */
@property (assign, nonatomic) CGFloat descriptionOffsetX;
@property (assign, nonatomic) LGPlusButtonsAppearingAnimationType appearingAnimationType;
@property (assign, nonatomic) LGPlusButtonsAppearingAnimationType buttonsAppearingAnimationType;
@property (assign, nonatomic) LGPlusButtonAnimationType plusButtonAnimationType;
@property (assign, nonatomic) LGPlusButtonsViewPosition position;
- (void)setButtonsTitles:(NSArray *)titles forState:(UIControlState)state;
- (void)setButtonsTitleColor:(UIColor *)titleColor forState:(UIControlState)state;
- (void)setButtonsImage:(UIImage *)image forState:(UIControlState)state;
- (void)setButtonsBackgroundImage:(UIImage *)backgroundImage forState:(UIControlState)state;
- (void)setButtonsBackgroundColor:(UIColor *)backgroundColor forState:(UIControlState)state;
- (void)setButtonsTitleFont:(UIFont *)font;
- (void)setDescriptionsTexts:(NSArray *)texts;
- (void)setDescriptionsTextColor:(UIColor *)textColor;
- (void)setDescriptionsBackgroundColor:(UIColor *)backgroundColor;
- (void)setDescriptionsFont:(UIFont *)font;
- (void)setButtonsClipsToBounds:(BOOL)clipsToBounds;
- (void)setButtonsContentEdgeInsets:(UIEdgeInsets)contentEdgeInsets;
- (void)setButtonsAdjustsImageWhenHighlighted:(BOOL)adjustsImageWhenHighlighted;
- (void)setButtonsLayerMasksToBounds:(BOOL)masksToBounds;
- (void)setButtonsLayerCornerRadius:(CGFloat)cornerRadius;
- (void)setButtonsLayerBorderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth;
- (void)setButtonsLayerShadowColor:(UIColor *)shadowColor shadowOpacity:(float)shadowOpacity shadowOffset:(CGSize)shadowOffset shadowRadius:(CGFloat)shadowRadius;
Чтобы показывать или скрывать LGPlusButtonsView, предусмотрены следующие методы:
// для всех кнопок, включая кнопку "+"
- (void)showAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)hideAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
// только дополнительные кнопки
- (void)showButtonsAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)hideButtonsAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
LGFilterView
Довольно часто в новостных приложениях приходится делать фильтры, к примеру, для выбора категории выводимых материалов. Логика у них вполне похожа, обычно это выпадающая таблица с названиями. Данный функционал и реализует LGFilterView.
Краткий список возможностей:
- Может показывать по умолчанию как таблицу, так и кастомную вьюху
- Есть несколько стилей на выбор
- Довольно широкие возможности по настройке внешнего вида
Инициализировать можно либо со списком возможных названий (тогда фильтр будет выглядеть как таблица), либо со своей кастомной вьюхой (которую фильтр будет показывать):
- (instancetype)initWithView:(UIView *)view;
- (instancetype)initWithTitles:(NSArray *)titles;
События отлавливаются с помощью делегирования, блоков и нотификаций:
@property (assign, nonatomic) id<LGFilterViewDelegate> delegate;
- (void)filterViewWillShow:(LGFilterView *)filterView;
- (void)filterViewWillDismiss:(LGFilterView *)filterView;
- (void)filterViewDidShow:(LGFilterView *)filterView;
- (void)filterViewDidDismiss:(LGFilterView *)filterView;
- (void)filterView:(LGFilterView *)filterView buttonPressedWithTitle:(NSString *)title index:(NSUInteger)index;
- (void)filterViewCancelled:(LGFilterView *)filterView;
Блоки:
@property (strong, nonatomic) void (^willShowHandler)(LGFilterView *filterView);
@property (strong, nonatomic) void (^willDismissHandler)(LGFilterView *filterView);
@property (strong, nonatomic) void (^didShowHandler)(LGFilterView *filterView);
@property (strong, nonatomic) void (^didDismissHandler)(LGFilterView *filterView);
@property (strong, nonatomic) void (^actionHandler)(LGFilterView *filterView, NSString *title, NSUInteger index);
@property (strong, nonatomic) void (^cancelHandler)(LGFilterView *filterView);
NSNotifications:
kLGFilterViewWillShowNotification;
kLGFilterViewWillDismissNotification;
kLGFilterViewDidShowNotification;
kLGFilterViewDidDismissNotification;
Настройка внешнего вида и анимаций (по умолчанию анимации для iPhone и iPad различается):
@property (assign, nonatomic) LGFilterViewTransitionStyle transitionStyle;
@property (assign, nonatomic) CGPoint offset;
@property (assign, nonatomic) UIEdgeInsets contentInset;
@property (assign, nonatomic) CGFloat heightMax;
@property (assign, nonatomic, getter=isSeparatorsVisible) BOOL separatorsVisible;
@property (strong, nonatomic) UIColor *separatorsColor;
@property (assign, nonatomic) UIEdgeInsets separatorsEdgeInsets;
@property (strong, nonatomic) UIColor *titleColor;
@property (strong, nonatomic) UIColor *titleColorHighlighted;
@property (strong, nonatomic) UIColor *titleColorSelected;
@property (strong, nonatomic) UIColor *backgroundColorHighlighted;
@property (strong, nonatomic) UIColor *backgroundColorSelected;
@property (strong, nonatomic) UIFont *font;
@property (assign, nonatomic) NSUInteger numberOfLines;
@property (assign, nonatomic) NSLineBreakMode lineBreakMode;
@property (assign, nonatomic) NSTextAlignment textAlignment;
@property (assign, nonatomic) BOOL adjustsFontSizeToFitWidth;
@property (assign, nonatomic) CGFloat minimumScaleFactor;
@property (assign, nonatomic) CGFloat cornerRadius;
@property (assign, nonatomic) CGFloat borderWidth;
@property (strong, nonatomic) UIColor *borderColor;
@property (assign, nonatomic) UIScrollViewIndicatorStyle indicatorStyle;
Чтобы показывать или скрывать фильтр предусмотрены следующие методы:
- (void)showInView:(UIView *)view animated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)dismissAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
LGRefreshView
«Потяни, чтобы обновить» — очень модная фича, которая есть практически в каждом приложении. Даже Apple не удержалась и в iOS 6 добавила данный функционал, но почему-то только для UITableView, а UICollectionView и UIScrollView остались за бортом. Хотя при помощи некоторых костылей стандартный «pull to refresh» можно прикрутить и для UICollectionView, но костыли нам не нужны. По правде сказать различных «рефрешей» полно на гитхабе, сам долго искал подходящий, но в основном там либо заброшенные популярные старые версии, у которых накопился ворох различных проблем, или очень крутые библиотеки, которые делают просто невообразимые вещи, но слишком изощрены в дизайне, чтобы была возможность использовать их в любом проекте. Поэтому решил постараться сделать универсальный, кастомизируемый и нейтральный «pull to refresh».
При инициализации нужно указать родительскую вьюху, которая должна быть UIScrollView или наследуемым классом (UITableView или UICollectionView. По идее должно работать и с UIWebView, но во время тестов были проблемы, поэтому не советую).
- (instancetype)initWithScrollView:(UIScrollView *)scrollView;
Событие рефреша отлавливается с помощью делегирования, блоков и нотификаций:
@property (assign, nonatomic) id<LGRefreshViewDelegate> delegate;
- (void)refreshViewRefreshing:(LGRefreshView *)refreshView;
Блоки:
@property (strong, nonatomic) void (^refreshHandler)(LGRefreshView *refreshView);
NSNotifications:
kLGRefreshViewBeginRefreshingNotification;
kLGRefreshViewEndRefreshingNotification;
Для завершения обновления предусмотрен метод:
- (void)endRefreshing;
Также рефреш можно вызвать программно:
- (void)triggerAnimated:(BOOL)animated;
LGPlaceholderView
Если у вас клиент-серверное приложение, то при переходе на новый контроллер часто приходится загружать данные. Чтобы не фризить UI, делать это нужно в дополнительном потоке. Но что показывать пользователю, пока происходит загрузка? А показывать можно разное, для этого и сделан LGPlaceholderView.
Что LGPlaceholderView может показывать:
- Текст
- UIActivityIndicatorView
- Текст + UIActivityIndicatorView
- UIProgressView
- Текст + UIProgressView
- Кастомную вьюху
Кроме того, LGPlaceholderView всегда будет находиться поверх других вьюх. Вы можете загрузить данные, подготовить их к показу, а потом анимированно скрыть LGPlaceholderView.
При инициализации нужно указать вьюху, которую вы будете скрывать:
- (instancetype)initWithView:(UIView *)view;
События можно отлавливать с помощью нотификаций:
kLGPlaceholderViewWillShowNotification;
kLGPlaceholderViewWillDismissNotification;
kLGPlaceholderViewDidShowNotification;
kLGPlaceholderViewDidDismissNotification;
Для показа предусмотрены различные методы, в зависимости от того, какой стиль вы хотите задать:
- (void)showActivityIndicatorAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)showActivityIndicatorWithText:(NSString *)text animated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)showProgressViewAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)showProgressViewWithText:(NSString *)text animated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)showText:(NSString *)text animated:(BOOL)animated completionHandler:(void(^)())completionHandler;
- (void)showView:(UIView *)view animated:(BOOL)animated completionHandler:(void(^)())completionHandler;
Чтобы скрыть placeholder, нужно вызвать:
- (void)dismissAnimated:(BOOL)animated completionHandler:(void(^)())completionHandler;
Кроме того, различные стили можно комбинировать, если вы вызовите несколько «show» методов подряд, то LGPlaceholderView сменится на другой.
LGDrawer
Программное рисование изображений давно будоражит мой ум. Растровые картинки понемногу отмирают, даже apple в последних версиях xcode добавила поддержку для векторных изображений. Но что если не отягощать приложение дополнительными ресурсами, а рисовать изображения прямо внутри, благо инструменты позволяют.
Плюсы такого подхода, видящиеся мне:
- Качество изображений всегда на высоте, так как не требуется масштабирование, каждый девайс рисует именно то что нужно ему;
- Легкое и быстрое изменение содержимого (если, к примеру, необходимо поменять цвет, вместо того чтобы открывать редактор, загружать картинку, изменять цвет и сохранять, достаточно будет всего лишь поменять один параметр в коде);
- Облегчение веса конечного архива с приложением.
Так и появился LGDrawer. Посмотрим, что он может рисовать на данный момент:
- Прямоугольник (квадрат)
- Эллипс (круг)
- Треугольник
- Плюс
- Крест
- Линия
- Галочка
- Стрелочка
- Сердце
- Звезда
- Меню (3 параллельных линии с возможными точками)
- Различные тени
- Возможность накладывать изображения друг на друга, или вырезать одни изображения из других
#pragma mark - Rectangle
+ (UIImage *)drawRectangleWithImageSize:(CGSize)imageSize
size:(CGSize)size
offset:(CGPoint)offset
rotate:(CGFloat)degrees
roundedCorners:(UIRectCorner)roundedCorners
cornerRadius:(CGFloat)cornerRadius
backgroundColor:(UIColor *)backgroundColor
fillColor:(UIColor *)fillColor
strokeColor:(UIColor *)strokeColor
strokeThickness:(CGFloat)strokeThickness
strokeDash:(NSArray *)strokeDash
strokeType:(LGDrawerStrokeType)strokeType
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
#pragma mark - Ellipse
+ (UIImage *)drawEllipseWithImageSize:(CGSize)imageSize
size:(CGSize)size
offset:(CGPoint)offset
rotate:(CGFloat)degrees
backgroundColor:(UIColor *)backgroundColor
fillColor:(UIColor *)fillColor
strokeColor:(UIColor *)strokeColor
strokeThickness:(CGFloat)strokeThickness
strokeDash:(NSArray *)strokeDash
strokeType:(LGDrawerStrokeType)strokeType
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
#pragma mark - Triangle
/** Stroke type is center */
+ (UIImage *)drawTriangleWithImageSize:(CGSize)imageSize
size:(CGSize)size
offset:(CGPoint)offset
rotate:(CGFloat)degrees
cornerRadius:(CGFloat)cornerRadius
direction:(LGDrawerDirection)direction
backgroundColor:(UIColor *)backgroundColor
fillColor:(UIColor *)fillColor
strokeColor:(UIColor *)strokeColor
strokeThickness:(CGFloat)strokeThickness
strokeDash:(NSArray *)strokeDash
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
#pragma mark - Shadow
+ (UIImage *)drawShadowWithImageSize:(CGSize)imageSize
direction:(LGDrawerDirection)direction
backgroundColor:(UIColor *)backgroundColor
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
#pragma mark - Plus
+ (UIImage *)drawPlusWithImageSize:(CGSize)imageSize
size:(CGSize)size
offset:(CGPoint)offset
rotate:(CGFloat)degrees
thickness:(CGFloat)thickness
roundedCorners:(UIRectCorner)roundedCorners
cornerRadius:(CGFloat)cornerRadius
backgroundColor:(UIColor *)backgroundColor
fillColor:(UIColor *)fillColor
strokeColor:(UIColor *)strokeColor
strokeThickness:(CGFloat)strokeThickness
strokeDash:(NSArray *)strokeDash
strokeType:(LGDrawerStrokeType)strokeType
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
+ (UIImage *)drawPlusWithImageSize:(CGSize)imageSize
size:(CGSize)size
offset:(CGPoint)offset
rotate:(CGFloat)degrees
thickness:(CGFloat)thickness
backgroundColor:(UIColor *)backgroundColor
color:(UIColor *)color
dash:(NSArray *)dash
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
#pragma mark - Cross
+ (UIImage *)drawCrossWithImageSize:(CGSize)imageSize
size:(CGSize)size
offset:(CGPoint)offset
rotate:(CGFloat)degrees
thickness:(CGFloat)thickness
roundedCorners:(UIRectCorner)roundedCorners
cornerRadius:(CGFloat)cornerRadius
backgroundColor:(UIColor *)backgroundColor
fillColor:(UIColor *)fillColor
strokeColor:(UIColor *)strokeColor
strokeThickness:(CGFloat)strokeThickness
strokeDash:(NSArray *)strokeDash
strokeType:(LGDrawerStrokeType)strokeType
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
+ (UIImage *)drawCrossWithImageSize:(CGSize)imageSize
size:(CGSize)size
offset:(CGPoint)offset
rotate:(CGFloat)degrees
thickness:(CGFloat)thickness
backgroundColor:(UIColor *)backgroundColor
color:(UIColor *)color
dash:(NSArray *)dash
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
#pragma mark - Line
+ (UIImage *)drawLineWithImageSize:(CGSize)imageSize
length:(CGFloat)length
offset:(CGPoint)offset
rotate:(CGFloat)degrees
thickness:(CGFloat)thickness
direction:(LGDrawerLineDirection)direction
backgroundColor:(UIColor *)backgroundColor
color:(UIColor *)color
dash:(NSArray *)dash
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
#pragma mark - Tick
+ (UIImage *)drawTickWithImageSize:(CGSize)imageSize
size:(CGSize)size
offset:(CGPoint)offset
rotate:(CGFloat)degrees
thickness:(CGFloat)thickness
backgroundColor:(UIColor *)backgroundColor
color:(UIColor *)color
dash:(NSArray *)dash
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
#pragma mark - Arrow
+ (UIImage *)drawArrowWithImageSize:(CGSize)imageSize
size:(CGSize)size
offset:(CGPoint)offset
rotate:(CGFloat)degrees
thickness:(CGFloat)thickness
direction:(LGDrawerDirection)direction
backgroundColor:(UIColor *)backgroundColor
color:(UIColor *)color
dash:(NSArray *)dash
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
+ (UIImage *)drawArrowTailedWithImageSize:(CGSize)imageSize
size:(CGSize)size
offset:(CGPoint)offset
rotate:(CGFloat)degrees
thickness:(CGFloat)thickness
direction:(LGDrawerDirection)direction
backgroundColor:(UIColor *)backgroundColor
color:(UIColor *)color
dash:(NSArray *)dash
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
#pragma mark - Heart
/** Stroke type is center */
+ (UIImage *)drawHeartWithImageSize:(CGSize)imageSize
size:(CGSize)size
offset:(CGPoint)offset
rotate:(CGFloat)degrees
backgroundColor:(UIColor *)backgroundColor
fillColor:(UIColor *)fillColor
strokeColor:(UIColor *)strokeColor
strokeThickness:(CGFloat)strokeThickness
strokeDash:(NSArray *)strokeDash
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
#pragma mark - Star
/** Stroke type is center */
+ (UIImage *)drawStarWithImageSize:(CGSize)imageSize
size:(CGSize)size
offset:(CGPoint)offset
rotate:(CGFloat)degrees
backgroundColor:(UIColor *)backgroundColor
fillColor:(UIColor *)fillColor
strokeColor:(UIColor *)strokeColor
strokeThickness:(CGFloat)strokeThickness
strokeDash:(NSArray *)strokeDash
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
#pragma mark - Menu
+ (UIImage *)drawMenuWithImageSize:(CGSize)imageSize
size:(CGSize)size
offset:(CGPoint)offset
rotate:(CGFloat)degrees
thickness:(CGFloat)thickness
dotted:(BOOL)dotted
dotsPosition:(LGDrawerMenuDotsPosition)dotsPosition
dotsCornerRadius:(CGFloat)dotsCornerRadius
linesCornerRadius:(CGFloat)linesCornerRadius
backgroundColor:(UIColor *)backgroundColor
fillColor:(UIColor *)fillColor
strokeColor:(UIColor *)strokeColor
strokeThickness:(CGFloat)strokeThickness
strokeDash:(NSArray *)strokeDash
shadowColor:(UIColor *)shadowColor
shadowOffset:(CGPoint)shadowOffset
shadowBlur:(CGFloat)shadowBlur;
#pragma mark - Images
+ (UIImage *)drawImage:(UIImage *)image1
onImage:(UIImage *)image2
clear:(BOOL)clear;
+ (UIImage *)drawImageOnImage:(NSArray *)images;
+ (UIImage *)drawImagesWithFinishSize:(CGSize)finishSize
image1:(UIImage *)image1
image1Rect:(CGRect)rect1
image2:(UIImage *)image2
image2Rect:(CGRect)rect2
clear:(BOOL)clear;
+ (UIImage *)drawImagesWithFinishSize:(CGSize)finishSize
image1:(UIImage *)image1
image1Offset:(CGPoint)offset1
image2:(UIImage *)image2
image2Offset:(CGPoint)offset2
clear:(BOOL)clear;
Принцип рисования следующий. У каждого метода есть параметры, где вы можете задавать размер области (холста), в которой будет находиться изображения, её заливку; размер самого изображения, его заливку, обводку, тень, смещение относительно центра внутри холста, угол поворота изображения и, если возможно, толщину линий и закругления углов.
Не все параметры удалось реализовать для каждого метода, но старался по максимуму возможного.
Было бы очень интересно, если сообщество помогло расширить возможности данной библиотеки. Во-первых, добавить недостающие параметры там, где этого не смог я. Во-вторых, увеличить каталог возможных изображений.
LGViews
Часто хочется расширить функционал той или иной вьюхи. Почему для UILabel нельзя задать contentEdgeInsets? Если я хочу расположить UILabel поверх картинки, то для удобства чтения текста, вместо того, чтобы расширить background, приходится создавать дополнительную UIView. Или для UIButton, почему для каждого состояния можно задать текст, цвета текста, картинку, картинку background'a, но банального цвета background'a задать нельзя. А что насчет выбора расположения картинки относительно текста?
В общем, думаю, вы поняли направление моих мыслей, в этой библиотеке я написал классы, которые расширяют возможности стандартных вьюх:
- contentEdgeInsets для UILabel
- backgroundColor для разных состояний UIButton
- Возможность задать UIButton не прямоугольную форму за счет масок
- Выбрать расположение картинки относительно текста в UIButton
- Задание максимальной длины текста для UITextField и UITextView
- contentEdgeInsets для текста и боковых изображений в UITextField
- Удаление лишних пробелов и переносов строк из UITextField
- Возможность авторасширения для UITextView с заданием максимальной высоты или количества строк
- placeholder для UITextView
LGViewControllers
Так же обстоят дела и с UIViewController'ами. Но тут расширять возможности было сложнее и не так очевидно, поэтому не считаю, что смог в полной мере добиться желаемого результата.
Краткий список:
- Добавил UIScrollViewController и UIWebViewController
- Для UITableViewController, UICollectionViewController и UIScrollViewController добавил LGRefreshView и LGPlaceholderView; для UIWebViewController только LGPlaceholderView
- Для UITableViewControlle добавил новый метод делегата «heightForRowAtIndexPathAsync», который позволяет асинхронно рассчитывать высоту ячеек. То есть, если у вас динамическая высота ячеек и вы часто подгружаете список, данный метод поможет избежать задержек в интерфейсе
- Для UICollectionViewController попытался упростить инициализацию layout'а, чтобы можно было настроить сетку без лишних рассчетов
- UIWebViewController можно использовать без наследования, а сразу передавать в тело ссылку на нужный ресурс при инициализации
- Добавил методы для автоматического слежения за клавиатурой, то есть contentInsets будут меняться при появлении и исчезновении клавиатуры
LGHelper, LGHelper+NS, LGHelper+UI
Каждый день мы решаем огромное количество повторяющихся задач. Большинство из них мы помним, но часто мелкие детали реализации ускользают и приходится периодически освежать их в памяти. Данные хелперы — это библиотеки, содержащие в себе всевозможные макроссы и методы, помогающие в повседневной жизни. Я собрал здесь довольно много полезной информации, не обязательно даже использовать их в своих проектах, иногда полезно бывает просто заглянуть, чтобы вспомнить ту или иную фичу.
Обработка изображений, конвертация цветов, использование масок, отправка электронных писем, вызов звонка с подтверждением и без, показ местоположения на карте, узнать состояние подключения к интернету, добавить человека в адресную книгу, закодировать данные, получить MD5 и SHA1 хэши, добавить событие в календарь, получить изображение с камеры… и многое многое другое, что я не буду здесь перечислять. Думаю названия всех методов и переменных должны быть более-менее интуитивно понятны, поэтому, чтобы ознакомиться с полным списком возможностей, предлагаю просмотреть header файлы исходников.
LGSharing, LGAudioStreamHelper, LGConnection
Эти 3 библиотеки, на мой взгляд, не так интересны как остальные. LGSharing ясное дело помогает постить в социальные сети (ВКонтакте, Facebook и Twitter) + отправлять сообщения на email и sms. LGConnection является оберткой вокруг AFNetworking, из коробки может парсить ответ от сервера включая XML формат + имеет логику для обработки прерывания интернет соединения. LGAudioStreamHelper помогает работать с аудио стримами, определять формат, получать метаданные и записывать поток. Более подробно рассказывать не буду, если кому интересно, заходите на гитхаб и пробуйте.
Всем спасибо за внимание. Буду очень рад если мои труды кому-то принесут пользу. Открыт для объективной критики, предложениям по улучшению или расширению функционала библиотек. Если есть какие вопросы — задавайте, постараюсь ответить.
Комментарии (26)
Error1024
15.07.2015 00:18+2Еще не программировал под iOS, но всё равно спасибо!
Колоссальный и полезный труд.
Вот бы так все разрабочики и компании делали при смене/прекращении деятельности, а не прятали полезные наработки гнить в дальний угол жестких дисков.
InstaRobot
15.07.2015 02:24+3А что не так с iOS-разработкой?
Headmast
15.07.2015 09:15Думаю за 5 лет надоело.
NayZaK
15.07.2015 09:22+1Если автор под вебом понимает нечто серьезное, то его можно понять. Но если же имеется ввиду всякие там css, js, php, то это явно шаг назад. Отсюда и вопрос.
namc
15.07.2015 11:45В профиле автора написанно, что RoR. NayZaK, это шаг назад?
Friend_LGA 20, спасибо за статью.NayZaK
15.07.2015 12:32Опять же смотря что делать на этих рельсах. Но в целом пять лет воевать с xcode, вникать в тонкости obj-c, изучать эпловские фрэймворки, бороться за каждый мегабайт памяти, за отсутствие лагов и падений, продумывать архитектуру приложения, чтобы вот так вот взять и метнуться на рельсы? Странно это. Я к тому, что человек долгое время изучал инструмент и приучал себя к оптимизациям, а теперь внезапно рельсы. Они-то уж точно не про оптимизацию. Ровно как и другие вебовские приблуды для скриптовых языков.
esc
15.07.2015 17:27Серверный код, который обслуживает миллионы пользователей может быть интереснее с архитектурной точки зрения. Особенно, если objc и клиентская разработка банально надоела.
Friend_LGA Автор
16.07.2015 22:02Если это действительно кому-то интересно, то постараюсь сформулировать…
Работа для меня (по крайней мере сейчас) — это скорее способ саморазвития и поиска себя. Когда я начал заниматься iOS, мобильный рынок, впрочем как и сейчас, был очень быстрорастущим и хотелось ухватить свой кусок пирога. Но оказалось, что все не так просто, как казалось. Если брать в расчет чисто мобильное приложение, без какого-либо бэкграунда, то что это может быть? Игра или оффлайн-приложение типа «купи батон». Да, таких много, и встречаются действительно поражающие экземпляры, например как «Flappy Bird», но это скорее исключение из правил. Поработав в индустрии, ко мне пришло понимание, что если делать что-то серьезное, то мобильное приложение это скорее дополнение, компаньон, для внешнего сервиса. А внешний сервис это что? В основном это веб сайты. Поэтому решил идти глубже и изучать веб.
Почему Ruby on Rails? Ну… в нашем городе не сказать чтобы очень большой выбор, а поработать в команде со знающими людьми, это уже не плохое подспорье. Все равно главное — это понять суть, внутреннее устройство, как связываются между собой frontend и backend, а рельсы это просто инструмент, коих много, и чтобы выбрать то что нравится нужно пробовать.
Не претендую на истину в последней инстанции, все что сказал выше это мое ИМХО, прошу не принимать сильно близко к сердцу.
storoj
15.07.2015 04:34+1- В LGDrawer какой-нибудь билдер бы, чтобы простые фигуры можно было сконфигурировать всего парой параметров, а остальные были бы по-умолчанию нулями. Легко было бы добавлять новые настройки фигур, не меняя весь пользовательский код.
- Вместо __attribute__((unavailable)) наверное стоило бы заюзать NS_DESIGNATED_INITIALIZER
- NS_ENUM для красоты
- if (_type == LGPlaceholderViewTypeText) {… } else if (_type == LGPlaceholderViewTypeActivityIndicator) { ...} else if ...
- /** Do not forget about weak referens to self */ – а на не self значит можно болт забить? от этого «self» у меня аж болит всё
- cornerRadius+masksToBounds+shadowOffset с анимациями очень плохо влияют на производительность
- — (UIView *)leftView { return _leftView; } – почему не readonly property?
- animateStandart… -> animateStandard
Friend_LGA Автор
16.07.2015 22:21В LGDrawer пытался по началу делать несколько методов с разным количеством параметров, но в итоге мозг совсем запутался, какие параметры нужны больше, какие меньше, в итоге плюнул и оставил только общие конструкторы. Хотя я с вами согласен, выглядит немного громоздко.
Насчет «switch — case» коллеги пинают уже не первый год, но все никак не могу постичь дзен и начать его использовать, спасибо за очередной пинок :)
/** Do not forget about weak referens to self */ – а на не self значит можно болт забить? от этого «self» у меня аж болит всё
Не совсем понял… Когда блок задан как strong, то если мы внутри него обратимся к self — получим retain cycle. Чтобы этого избежать нужно делать как-то так:
__weak typeof(self) wself = self; block = ^(void) { if (wself) { __strong typeof(wself) self = wself; ... } };
cornerRadius+masksToBounds+shadowOffset с анимациями очень плохо влияют на производительность
Конечно нужно использовать с умом. Но в целом для современных девайсов все не так критично как раньше.
Насчет остального спасибо, учту, в ближайшее время постараюсь исправитьFriend_LGA Автор
16.07.2015 22:26— (UIView *)leftView { return _leftView; } – почему не readonly property?
Ну по большому счету разницы особой нет. Не помню уже точно, но вроде бы, если глобально и приватно объявляешь одинаковые переменные с разными классами, вылезают варнинги.
Pr0Ger
17.07.2015 00:05Не совсем понял… Когда блок задан как strong, то если мы внутри него обратимся к self — получим retain cycle. Чтобы этого избежать нужно делать как-то так:
Это конечно да, просто retain цикл можно не только из-за self получать; так-же как можно использовать self внутри блока без weak ссылки и не получить утечек памяти
askl
15.07.2015 04:57+1Отличная подборка! Спасибо!
А можно в LGSharing добавить инстаграм еще?Friend_LGA Автор
16.07.2015 22:37Пожалуйста!
Насчет LGSharing — как я уже писал в статье, от iOS разработки я отошел и сейчас занимаюсь вебом, поэтому времени добавлять новый функционал сейчас у меня нет, готов только править критичные баги. Но pull-request'ы на гитхабе приветствуются :)
DenFav
15.07.2015 12:10Занимаюсь разработкой только год… Это прекрасная подборка Ваших наработок. Большое спасибо!
Lonkly
15.07.2015 15:54Спасибо за шаринг, рекомендую Вам поделиться вашими подсами на Cocoa Controls :) Распиарите так свой гитхаб, например :)
i_user
Очень качественный и удобный джентельменский набор! Благодарю вас)
Friend_LGA Автор
Рад стараться :)