Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Here's a working demo</p> <h2>AppDelegate</h2> <pre><code>inline static CGPoint CGRectGetCenter( CGRect r ) { return (CGPoint){ CGRectGetMidX( r ), CGRectGetMidY( r ) } ; } @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; CGFloat size = 300.0 ; for( int index =0; index &lt; 10; ++index ) { RingView * view = [[ RingView alloc ] initWithFrame:(CGRect){ .size = { size, size } } ] ; view.outerRadius = size * 0.5 ; view.innerRadius = view.outerRadius - 20.0 ; view.center = CGRectGetCenter( self.window.bounds ) ; [ self.window addSubview:view ] ; size -= 20.0 ; } return YES; } -(void)ringViewTapped:(RingView*)sender sliceIndex:(NSNumber*)sliceIndex { [ UIView animateWithDuration:0.25 animations:^{ sender.transform = CGAffineTransformMakeRotation( -[ sliceIndex doubleValue ] * M_PI_2 ) ; } ] ; } @end </code></pre> <h2>RingView</h2> <pre><code>@interface RingView : UIControl @property ( nonatomic ) CGFloat innerRadius, outerRadius ; @end @implementation UIResponder (Send) -(BOOL)sendMessage:(SEL)message withObject:(id)obj0 withObject:(id)obj1 { UIResponder * target = self ; do { if ( [ target respondsToSelector:message ] ) { [ target performSelector:message withObject:obj0 withObject:obj1 ] ; return YES ; } target = [ target nextResponder ] ; } while( target ) ; return NO ; } @end @implementation UIColor (RandomColor) +(UIColor*)randomColor { return [ UIColor colorWithHue:((CGFloat)arc4random_uniform( 6 ) / 6.0) saturation:1.0 brightness:1.0 alpha:1.0 ] ; } @end static CGPathRef CGPathCreateWedge( CGFloat innerRadius, CGFloat outerRadius ) { CGMutablePathRef p = CGPathCreateMutable() ; CGPathMoveToPoint( p, NULL, 0, innerRadius ) ; CGPathAddLineToPoint( p, NULL, 0, outerRadius ) ; CGPathAddArcToPoint( p, NULL, outerRadius, outerRadius, outerRadius, 0.0, outerRadius ) ; CGPathAddLineToPoint( p, NULL, innerRadius, 0.0 ) ; CGPathAddArcToPoint( p, NULL, innerRadius, innerRadius, 0.0, innerRadius, innerRadius ) ; CGPathCloseSubpath( p ) ; return p ; } @interface RingView () @end @implementation RingView -(void)_ensureSlices { if ( self.layer.sublayers.count == 0 ) { CGPathRef p = CGPathCreateWedge( self.innerRadius, self.outerRadius ) ; for( int index=0; index &lt; 4; ++index ) { CAShapeLayer * layer = [ CAShapeLayer layer ] ; layer.path = p ; { CGColorRef c = [ [ UIColor randomColor ] CGColor ] ; layer.fillColor = c ; CGColorRelease( c ) ; } layer.transform = CATransform3DMakeRotation( (CGFloat)index * M_PI_2 - M_PI_4, 0.0, 0.0, 1.0 ) ; [ self.layer addSublayer:layer ] ; } CGPathRelease( p ) ; } } -(id)initWithFrame:(CGRect)frame { self = [ super initWithFrame:frame ] ; [ self addTarget:nil action:@selector( tapped:event: ) forControlEvents:UIControlEventTouchUpInside ] ; return self ; } -(void)layoutSubviews { [ self _ensureSlices ] ; CGRect bounds = self.bounds ; self.bounds = (CGRect){ { -0.5f * bounds.size.width, -0.5f * bounds.size.height }, bounds.size } ; } -(UIView *)hitTest:(CGPoint)p withEvent:(UIEvent *)e { UIView * result = [ super hitTest:p withEvent:e ] ; if ( result == self ) { CGFloat r = sqrt( p.x * p.x + p.y * p.y ) ; if ( r &lt; self.innerRadius || r &gt; self.outerRadius ) { return nil ; } } return result ; } -(IBAction)tapped:(id)sender event:(UIEvent*)event { CGPoint p = [ [ [ event touchesForView:self ] anyObject ] locationInView:self ] ; int index = 0 ; for( CAShapeLayer * layer in self.layer.sublayers ) { CGPoint testPoint = [ layer convertPoint:p fromLayer:self.layer ] ; if ( CGPathContainsPoint( layer.path, NULL, testPoint, false ) ) { [ self sendMessage:@selector( ringViewTapped:sliceIndex: ) withObject:self withObject:@( index ) ] ; } ++index ; } } -(void)setOuterRadius:(CGFloat)r { _outerRadius = r ; [[self.layer.sublayers copy ] makeObjectsPerformSelector:@selector( removeFromSuperlayer ) ] ; [ self setNeedsLayout ]; } -(void)setInnerRadius:(CGFloat)r { _innerRadius = r ; [[self.layer.sublayers copy ] makeObjectsPerformSelector:@selector( removeFromSuperlayer ) ] ; [ self setNeedsLayout ]; } @end </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload