После длительного перерыва решил опубликовать новый пост в блоге.
Традиционно все UIView в iOS имеют прямоугольную форму. И с помощью полупрозрачного цвета (так-же изображений с alpha каналом) и порядком (z-order) наложения вью друг на друга можно добиваться практически всего, что можно вообразить. Но вот понадобился мне полупрозрачный свой UISwitch в котором был предопределен порядок вьюшек.
И что б этот пост не был постом об одном методе, опишу процесс создания компоненты.
Есть изображения:
1. подложка компоненты
2. маска под эту подложку
3. включенное
и выключенное
состояния
Наследоваться будем от UIView.
В методе init будем создавать вью которые нам и понадобятся.
_backgroundImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"butt_bg"]];
[self addSubview:_backgroundImage];
создаем подложку компоненты и добавляем ее на родительское вью
UIView *maskedView = [[UIView alloc] initWithFrame:self.bounds];
maskedView.backgroundColor = [UIColor clearColor];
[self addSubview:maskedView];
создаем вью, к которому будет примененна маска, на него будем ложить дальше компоненты для того, что б они не вылазили за пределы внутреннего "овала"
_backgroundView = [[UIScrollView alloc] initWithFrame:self.bounds];
_backgroundView.backgroundColor = [UIColor clearColor];
_backgroundView.clipsToBounds = YES;
_backgroundView.delegate = self;
_backgroundView.clearsContextBeforeDrawing = NO;
_backgroundView.pagingEnabled = YES;
_backgroundView.showsVerticalScrollIndicator = NO;
_backgroundView.showsHorizontalScrollIndicator = NO;
_backgroundView.scrollsToTop = NO;
_backgroundView.contentSize = CGSizeMake(105.0, _backgroundView.bounds.size.height);
_backgroundView.bounces = NO;
[maskedView addSubview:_backgroundView];
_onLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_onLabel.backgroundColor = [UIColor clearColor];
_onLabel.opaque = NO;
_onLabel.textColor = [UIColor blackColor];
_onLabel.font = [UIFont boldSystemFontOfSize:16.0];
_onLabel.textAlignment = UITextAlignmentCenter;
_onLabel.text = NSLocalizedString(@"ON", nil);
_onLabel.frame = CGRectMake(0.0, 0.0, 43.0, _backgroundView.frame.size.height);
[_backgroundView addSubview:_onLabel];
UIImage *img = [UIImage imageNamed:@"r_butt_on"];
_ballImage0 = [[UIImageView alloc] initWithImage:img];
_ballImage0.frame = CGRectMake((_backgroundView.contentSize.width-img.size.width)/2.0,
(_backgroundView.contentSize.height-img.size.height)/2.0,
img.size.width, img.size.height);
[_backgroundView addSubview:_ballImage0];
img = [UIImage imageNamed:@"r_butt_off"];
_ballImage1 = [[UIImageView alloc] initWithImage:img];
_ballImage1.frame = _ballImage0.frame;
_ballImage1.alpha = 0.0;
[_backgroundView addSubview:_ballImage1];
_offLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_offLabel.backgroundColor = [UIColor clearColor];
_offLabel.opaque = NO;
_offLabel.textColor = [UIColor blackColor];
_offLabel.font = [UIFont boldSystemFontOfSize:16.0];
_offLabel.textAlignment = UITextAlignmentCenter;
_offLabel.text = NSLocalizedString(@"OFF", nil);
_offLabel.frame = CGRectMake(60.0, 0.0, 43.0, _backgroundView.frame.size.height);
[_backgroundView addSubview:_offLabel];
тут
_backgroundView - скролл который будет анимированно двигаться, котда будем прикасаться к нему, на нем лежит две текстовые метки:
_onLabel и
_offLabel которые просто отображают текст и вьюшки с включенной и выключенной лампочками (
_ballImage0 и
_ballImage1).
А вот и подобрались к самому главному, создаем слой маски из изображения и применяем его к вью:
UIImage *_maskingImage = [UIImage imageNamed:@"butt_mask"];
CALayer *_maskingLayer = [CALayer layer];
_maskingLayer.frame = CGRectMake(1.0, 1.0, self.bounds.size.width-2.0, self.bounds.size.height-2.0);
[_maskingLayer setContents:(id)[_maskingImage CGImage]];
maskedView.layer.mask = _maskingLayer;
Регистрируем слушателя на касание внутри нашей компоненты:
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleSingleTap:)];
[self addGestureRecognizer:singleFingerTap];
[singleFingerTap release];
и обработчик этого одиночного касания (до этого мы все делали в методе
init):
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer
{
[self setOn:!_on animated:YES];
}
так-же методы установки/получения состояния компоненты:
- (void)setOn:(BOOL)on animated:(BOOL)animated
{
_on = on;
_scrollingAnimation = animated;
[_backgroundView setContentOffset:CGPointMake(on?0.0:_backgroundView.contentSize.width-self.bounds.size.width, 0.0) animated:animated];
_ballImage0.alpha = _on?1.0f:.0f;
_ballImage1.alpha = _on?.0f:1.0f;
}
- (void)setOn:(BOOL)on
{
[self setOn:on animated:NO];
}
- (BOOL)on
{
return _on;
}
тут в зависимости от состояния меняем прозрачность наших изображений
_ballImage0 и
_ballImage1 ну и храним состояние в переменной
_on
и обработчики перемещения UIScrollView пользователем:
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
CGFloat koof = sender.contentOffset.x/(sender.contentSize.width-sender.bounds.size.width);
_ballImage0.alpha = 1.0f-koof;
_ballImage1.alpha = koof;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
if (!_scrollingAnimation)
{
self.on = _backgroundView.contentOffset.x<1.0;
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (!decelerate && !_scrollingAnimation)
{
self.on = _backgroundView.contentOffset.x<1.0;
}
}
Вот и все, проект можно посмотреть на
github-е, в нем специально закомментирована строка
_backgroundView.bounces = NO;, для более наглядной демонстрации эффекта.
ЗЫ:
Вот еще одно интересное применение маски.