Традиционно все 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;, для более наглядной демонстрации эффекта.
ЗЫ: Вот еще одно интересное применение маски.
Этот комментарий был удален администратором блога.
ОтветитьУдалить