CS175
Chris Pollett
Nov 12, 2014
#import <UIKit/UIKit.h> #import "Constants.h" @interface QuartzTestView : UIView @property (nonatomic, assign) CGPoint firstTouch; //assign keywords since C type @property (nonatomic, assign) CGPoint lastTouch; @property (nonatomic, assign) ShapeType shapeType; @property (nonatomic, assign) BOOL useRandomColor; @property (nonatomic, strong) UIColor *currentColor; @property (nonatomic, strong) UIImage *drawImage; @end
Here is the implementation of QuartzTestView. The drawRect method is where we override the base UIView ways of drawing things. We also have code to handle touch events (when they start, end and how they change).
#import "QuartzTestView.h" #import "UIRandomColor.h" @implementation QuartzTestView //we're using initWithCoder as we are loading the view from a nib // and so init and initWithFrame will never be called -(id)initWithCoder:(NSCoder *)coder { if((self = [super initWithCoder:coder])) { _currentColor = [UIColor redColor]; _useRandomColor = NO; _drawImage = [UIImage imageNamed:@"myphoto.jpg"]; } return self; } // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 2.0); CGContextSetStrokeColorWithColor(context, _currentColor.CGColor); CGContextSetFillColorWithColor(context, _currentColor.CGColor); CGRect currentRect = CGRectMake((_firstTouch.x > _lastTouch.x) ? _lastTouch.x : _firstTouch.x, (_firstTouch.y > _lastTouch.y) ? _lastTouch.y : _lastTouch.y, fabsf(_firstTouch.x - _lastTouch.x), fabsf(_firstTouch.y - _lastTouch.y)); switch (_shapeType) { case kLineShape: CGContextMoveToPoint(context, _firstTouch.x, _firstTouch.y); CGContextAddLineToPoint(context, _lastTouch.x, _lastTouch.y); CGContextStrokePath(context); break; case kRectShape: CGContextAddRect(context, currentRect); CGContextDrawPath(context, kCGPathFillStroke); break; case kEllipseShape: CGContextAddEllipseInRect(context, currentRect); CGContextDrawPath(context, kCGPathFillStroke); break; case kImageShape: { CGFloat horizontalOffset = _drawImage.size.width/2; CGFloat verticalOffset = _drawImage.size.height/2; CGPoint drawPoint = CGPointMake(_lastTouch.x - horizontalOffset, _lastTouch.y - verticalOffset); [_drawImage drawAtPoint:drawPoint]; break; } default: break; } } // Basic idea for touch handlers is to store in fields the touch info and redraw - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { if(_useRandomColor) { self.currentColor = [UIColor randomColor]; } UITouch *touch = [touches anyObject]; _firstTouch = [touch locationInView:self]; //store touch start info _lastTouch = [touch locationInView:self]; NSLog(@"hi there"); [self setNeedsDisplay]; // redraw view } - (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"hi there"); } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"hi there"); UITouch *touch = [touches anyObject]; _lastTouch = [touch locationInView:self]; [self setNeedsDisplay]; // redraw view } -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"hi there"); UITouch *touch = [touches anyObject]; _lastTouch = [touch locationInView:self]; [self setNeedsDisplay]; // redraw view } @end
#import <UIKit/UIKit.h> @interface ViewController : UIViewController @property (weak, nonatomic) IBOutlet UISegmentedControl *colorControl; @end
#import "ViewController.h" #import "Constants.h" #import "UIRandomColor.h" #import "QuartzTestView.h" @interface ViewController () @end @implementation ViewController - (IBAction)changeShape:(id)sender { UISegmentedControl *control = sender; ShapeType index = (ShapeType)[control selectedSegmentIndex]; [(QuartzTestView *)self.view setShapeType: index]; if(index == kImageShape) self.colorControl.hidden = YES; else self.colorControl.hidden = NO; } - (IBAction)changeColor:(id)sender { UISegmentedControl *control = sender; NSInteger index = [control selectedSegmentIndex]; QuartzTestView *quartzView = (QuartzTestView *)self.view; switch (index) { case kRedColorTab: quartzView.currentColor = [UIColor redColor]; quartzView.useRandomColor = NO; break; case kBlueColorTab: quartzView.currentColor = [UIColor blueColor]; quartzView.useRandomColor = NO; break; case kYellowColorTab: quartzView.currentColor = [UIColor yellowColor]; quartzView.useRandomColor = NO; break; case kGreenColorTab: quartzView.currentColor = [UIColor greenColor]; quartzView.useRandomColor = NO; break; case kRandomColorTab: quartzView.useRandomColor = YES; break; default: break; } } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
- (void) locationManager: (CLLocationManager *)manager didUpdateToLocation: (CLLocation *)newLocation fromLocation: (CLLocation *)oldLocation ; - (void) locationManager:(CLLocationManager *)manager didUpdateHeading: (CLHeading *)newHeading ; - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error ;to handle location and heading info, we implement the interface CLLocationManagerDelegate
#import <UIKit/UIKit.h> #import <CoreLocation/CoreLocation.h> #import <CoreMotion/CoreMotion.h> @interface SensorTestsViewController : UIViewController <CLLocationManagerDelegate> @property (weak, nonatomic) IBOutlet UILabel *locationLabel; @property (weak, nonatomic) IBOutlet UILabel *headingLabel; @property (weak, nonatomic) IBOutlet UILabel *accelerometerLabel; @property (strong, nonatomic) CLLocationManager *locationManager; @property (strong, nonatomic) CMMotionManager *motionManager; @property (strong, nonatomic) NSOperationQueue *queue; @end
#import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void) viewDidLoad { [super viewDidLoad]; _locationManager = [[CLLocationManager alloc] init]; _locationManager.delegate = self; _locationManager.desiredAccuracy = kCLLocationAccuracyBest; [_locationManager startUpdatingLocation]; [_locationManager startUpdatingHeading]; _motionManager = [[CMMotionManager alloc] init]; if(_motionManager.accelerometerAvailable) { _motionManager.accelerometerUpdateInterval = 1.0/10.0;/* how many times a second to send acclerometer updates. Shouldn't do too fast or battery dies. */ [_motionManager startAccelerometerUpdatesToQueue:_queue withHandler: ^(CMAccelerometerData *accelerometerData, NSError *error) { NSString *labelText; if(error) { [_motionManager stopAccelerometerUpdates]; labelText = [NSString stringWithFormat:@"Accelerometer encountered error %@", error]; } else { labelText = [NSString stringWithFormat:@"Accelerometer\n--\n" "x: %+.2f\ny:%+.2f\nz:%+.2f", accelerometerData.acceleration.x, accelerometerData.acceleration.y, accelerometerData.acceleration.z]; } dispatch_async(dispatch_get_main_queue(), ^{ _accelerometerLabel.text = labelText; }); }]; } else { _accelerometerLabel.text = @"This Device has no accelerometer"; } } - (void) locationManager: (CLLocationManager *)manager didUpdateToLocation: (CLLocation *)newLocation fromLocation: (CLLocation *)oldLocation { NSString *loc = [[NSString alloc] initWithFormat:@"My Coordinates: %@", newLocation.description]; _locationLabel.text = loc; } - (void) locationManager:(CLLocationManager *)manager didUpdateHeading: (CLHeading *)newHeading { NSString *head = [[NSString alloc] initWithFormat:@"My Heading: %@", newHeading.description]; _headingLabel.text = head; } - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { if ([error code] == kCLErrorDenied) { [_locationManager stopUpdatingLocation]; } } @end
string.xml <?xml version="1.0" encoding="utf-8"?> <resources> <string name="xyz">Acceleration: X: Y: Z:</string> <string name="app_name">AccelerometerDemo</string> </resources>
main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/xyz" android:id="@+id/acceleration" /> </LinearLayout>
public void onSensorChanged(SensorEvent event); public void onAccuracyChanged(Sensor arg0, int arg1);We really only care about code in the former method.
package org.pollett; import java.util.List; import android.app.Activity; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.widget.TextView; public class AccelerometerDemo extends Activity implements SensorEventListener { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); accelerationLabel = (TextView )this.findViewById(R.id.acceleration); manager = (SensorManager)getSystemService(SENSOR_SERVICE); List<Sensor> list = manager.getSensorList(Sensor.TYPE_ACCELEROMETER); if(list != null && list.size() > 0) { accelerometer = list.get(0); } } @Override public void onResume() { super.onResume(); if(accelerometer != null) { manager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL); } } @Override public void onPause() { super.onPause(); if(accelerometer != null) { manager.unregisterListener(this); } } public void onAccuracyChanged(Sensor arg0, int arg1) { } public void onSensorChanged(SensorEvent event) { accelerationLabel.setText("Acceleration X:" + event.values[0] + " Y:" + event.values[1] + " Z:" + event.values[2]); } protected TextView accelerationLabel; protected SensorManager manager; protected Sensor accelerometer; }