Нарисуйте треугольник вырез для индикации выбора в UIView - PullRequest
16 голосов
/ 02 октября 2011

Я создаю представление, которое служит селектором категории для моего приложения. Мне бы хотелось, чтобы в качестве индикатора выбора был вырезанный треугольник, как на этом изображении:

Custom UI design

Я не уверен, как нарисовать треугольник так, чтобы он был вырезом, показывая основной вид внизу. Основной вид снизу, скорее всего, будет иметь собственное, возможно, неповторяющееся (я еще не решил) изображение в качестве фона. Кроме того, я хотел бы, чтобы треугольник анимировался в новом месте при изменении выделения, что еще более усложняет ситуацию.

Я понимаю, что подпредставление облегчило бы анимацию, но усложнило бы рисование; прямое рисование, вероятно, сделает анимацию немного сложнее. И я не слишком знаком с Кварцем, поэтому я не уверен, что делать с маршрутом прямого рисования.

Заранее спасибо!

Обновление: Я посмотрел на пост Мэтта Галлахера о рисовании фигур с отверстиями , но на самом деле он не отвечает на мой вопрос. Есть ли способ для меня, чтобы «увидеть», что находится под определенным путем в моей форме, и скопировать это? ... а потом поддерживаете анимацию?

Обновление 2: Я сделал частичную работу, просто нарисовав дополнительный путь. Результат выглядит так: http://dl.dropbox.com/u/7828009/Category%20Selector.mov

код:

CGRect cellRect = [self rectForCategoryNumber:(selectedCategoryIndex + 1)];
[[UIColor scrollViewTexturedBackgroundColor] setFill];
CGContextMoveToPoint(currentContext, self.frame.size.width, (cellRect.origin.y + cellRect.size.height * 0.15));
CGContextAddLineToPoint(currentContext, self.frame.size.width, (cellRect.origin.y + cellRect.size.height * 0.65));
CGContextAddLineToPoint(currentContext, self.frame.size.width * 0.8, (cellRect.origin.y + cellRect.size.height * 0.4));
CGContextClosePath(currentContext);
CGContextFillPath(currentContext);
[[UIColor darkGrayColor] setStroke];
CGContextSetLineCap(currentContext, kCGLineCapRound);
CGContextMoveToPoint(currentContext, self.frame.size.width, (cellRect.origin.y + cellRect.size.height * 0.15));
CGContextAddLineToPoint(currentContext, self.frame.size.width * 0.8, (cellRect.origin.y + cellRect.size.height * 0.4));
CGContextSetLineWidth(currentContext, 2.5);
CGContextStrokePath(currentContext);
[[UIColor lightGrayColor] setStroke];
CGContextMoveToPoint(currentContext,self.frame.size.width * 0.8, (cellRect.origin.y + cellRect.size.height * 0.4));
CGContextAddLineToPoint(currentContext, self.frame.size.width, (cellRect.origin.y + cellRect.size.height * 0.65));
CGContextSetLineWidth(currentContext, 1.0);
CGContextStrokePath(currentContext);

Очевидно, что в этом случае это работает только потому, что я использую один и тот же цвет заливки в обоих случаях; Я хотел бы устранить эту зависимость, если это возможно. Также, конечно, я бы хотел оживить положение этого треугольника.

Обновление 3: Что я пытался сделать для анимации:

static CALayer *previousLayer = nil;
static CGMutablePathRef previousPath = nil;
// … Get context, etc.
CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
shapeLayer.path = shapePath;
[shapeLayer setFillColor:[[UIColor redColor] CGColor]];
[shapeLayer setStrokeColor:[[UIColor blackColor] CGColor]];
[shapeLayer setBounds:self.bounds];
[shapeLayer setAnchorPoint:self.bounds.origin];
[shapeLayer setPosition:self.bounds.origin];
if (previousPath) {     // Animate change
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"changePath"];
    animation.duration = 0.5;
    animation.fromValue = (id)previousPath;
    animation.toValue = (id)shapePath;
    [shapeLayer addAnimation:animation forKey:@"animatePath"];
    previousPath = shapePath;
}

if (previousLayer)
    [previousLayer removeFromSuperlayer];
previousLayer = shapeLayer;
[self.layer addSublayer:shapeLayer];

1 Ответ

44 голосов
/ 04 октября 2011

Вы смотрели на CAShapeLayer ? Вы можете создать путь для панели выбора, который определяет весь контур, включая исключение треугольника для каждого состояния, которое необходимо замаскировать. Затем вы можете обводить слой, если хотите, чтобы контур, который вы показываете на своем изображении, установив свойства lineWidth и strokeColor. Это должно быть в состоянии дать вам то, что вам нужно. Свойство path в CAShapeLayer является анимируемым, что означает, что все, что вам нужно сделать, это установить свойство path, и оно будет анимироваться (при условии, что ваши слои являются подуровнями представления, а не корневым слоем).

С наилучшими пожеланиями.

Обновление с кодом

Этот код:

- (void)viewDidLoad
{
  [super viewDidLoad];

  [[self view] setBackgroundColor:[UIColor blueColor]];

  CGMutablePathRef path = CGPathCreateMutable();
  CGPathMoveToPoint(path,NULL,0.0,0.0);
  CGPathAddLineToPoint(path, NULL, 160.0f, 0.0f);  
  CGPathAddLineToPoint(path, NULL, 160.0f, 100.0f);
  CGPathAddLineToPoint(path, NULL, 110.0f, 150.0f);
  CGPathAddLineToPoint(path, NULL, 160.0f, 200.0f);
  CGPathAddLineToPoint(path, NULL, 160.0f, 480.0f);
  CGPathAddLineToPoint(path, NULL, 0.0f, 480.0f);
  CGPathAddLineToPoint(path, NULL, 0.0f, 0.0f);


  CAShapeLayer *shapeLayer = [CAShapeLayer layer];
  [shapeLayer setPath:path];
  [shapeLayer setFillColor:[[UIColor redColor] CGColor]];
  [shapeLayer setStrokeColor:[[UIColor blackColor] CGColor]];
  [shapeLayer setBounds:CGRectMake(0.0f, 0.0f, 160.0f, 480)];
  [shapeLayer setAnchorPoint:CGPointMake(0.0f, 0.0f)];
  [shapeLayer setPosition:CGPointMake(0.0f, 0.0f)];
  [[[self view] layer] addSublayer:shapeLayer];

  CGPathRelease(path);

}

Результаты на этом экране:

enter image description here

И вы можете скачать пример проекта здесь:

http://cl.ly/3J1B1f1l2423142l3X35

...