I am using a UIslider to move a UIImage left and right on the screen. When the UISlider is totally on the left the image will be to a certain position on the X atis on the left of the screen, and when the slider is totally to the right, the image is on the right of the screen. If for example I want to give the image flexibility movement of 600px, how can I do that?
-(IBAction)sliderValueChanged:(UISlider *)sender
{
if (sender.value >= 0.5) {
int value;
value = sender.value * 6;
[photoView setFrame:CGRectMake(photoView.frame.origin.x + value,
PhotoView.frame.origin.y,photoView.frame.size.width,photoView.frame.size.height)];
}else{
int value;
value = sender.value * -6;
[photoView setFrame:CGRectMake(photoView.frame.origin.x + value,
photoView.frame.origin.y,photoView.frame.size.width,photoView.frame.size.height)];
}
...this was my guess
I recently had to do the same thing you're trying to do for use in a full scale aircraft where the iPad/iPhone acts as a instrument gauge.
Here is the code I used to move an image for the aircraft's instrument readout: Also, you should round the float value to an int because we are dealing with whole pixel points. (The image will still move fine with a float value, but I like using an int when dealing with pixel points.)
#import "ViewController.h"
#import <math.h>
#interface ViewController()
#property (nonatomic, strong) IBOutlet UIImageView *XAxis;
#property (nonatomic, strong) IBOutlet UISlider *XSlider;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.XSlider.minimumValue = 0.0f;
self.XSlider.maximumValue = 600.0f;
}
- (IBAction)XValueChanged:(UISlider *)XSlider;
{
int XResult = (int)floorf(XSlider.value);
self.XAxis.center = CGPointMake(self.XAxis.center.x, XResult);
NSLog(#"X Value: %d", XResult);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
How about something like this,
slider.minimumValue = 0.0f;
slider.maximumValue = 600.0f;
-(IBAction)sliderValueChanged:(UISlider *)sender
{
[photoView setFrame:CGRectMake(sender.value, PhotoView.frame.origin.y,photoView.frame.size.width,photoView.frame.size.height)];
}
You can also do this by changing photoView.frame.origin.x + value to floatValue + value where floatValue is some fixed number based on where you want to set the photoView. Also calculate value as value = sender.value * constant where constant again depends on how much you need to move it for each slider movement.
Check documentation for more details on properties
Related
I would like to show the direction images on all sides of the screen. E.g. if the target's location is the right side of user's location and is outside of the visible map area, then I want to add a direction image as shown on the picture below (The Green annotation is user's location, red one is the direction for the target, which is out of bounds of the screen):
What is the standard approach to do this?
The simplest way is to place four "pointer" views above the map at each of the cardinal points. Then, as the user moves the map (using mapView:regionDidChangeAnimated: delegate method) determine which pointer should be shown. Hide all the other ones; and then show the correct one. Also, apply a transformation to the pointer so that the bearing angle is represented as you have done.
Here is a screenshot of a storyboard with the above configuration:
And here is a sample implementation (Code is not optimal, of course.):
//
// MapViewController.m
// AnimationTest
//
// Created by Scott Atkinson on 4/17/15.
//
#import "MapViewController.h"
#import MapKit;
typedef NS_ENUM(NSInteger, CardinalPoint) {
North,
South,
East,
West
};
#interface MapViewController () <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
// Views that show cardinal points on the map (Only one should be shown at a time)
#property (weak, nonatomic) IBOutlet UIView *northPointerView;
#property (weak, nonatomic) IBOutlet UIView *eastPointerView;
#property (weak, nonatomic) IBOutlet UIView *westPointerView;
#property (weak, nonatomic) IBOutlet UIView *southPointerView;
// Location to show on the map
#property (strong, nonatomic) CLLocation * targetLocation;
#end
#implementation MapViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self hidePointerViews];
// Add the location to the map
self.targetLocation = [[CLLocation alloc] initWithLatitude:37.331898 longitude:-122.029824];
MKPlacemark * placemark = [[MKPlacemark alloc] initWithCoordinate:self.targetLocation.coordinate addressDictionary:nil];
[self.mapView addAnnotation:placemark];
}
// ******************** MKMapViewDelegate ********************
#pragma mark - MKMapViewDelegate
// As the map moves, update the cardinal pointer views
- (void) mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
if([self isCurrentLocationVisible] && ![self isTargetLocationVisible]) {
// The user location is visible, but the target is not, so show a pointer
double bearing = [self bearingToLocation:self.targetLocation fromLocation:self.mapView.userLocation.location];
[self showCardinalPointDirection:bearing];
} else {
// Hide the pointers
[self hidePointerViews];
}
}
// ******************** Coordinate Helpers ********************
#pragma mark - Coordinate Helpers
- (BOOL) isCurrentLocationVisible {
return MKMapRectContainsPoint(self.mapView.visibleMapRect,
MKMapPointForCoordinate(self.mapView.userLocation.coordinate));
}
- (BOOL) isTargetLocationVisible {
return MKMapRectContainsPoint(self.mapView.visibleMapRect,
MKMapPointForCoordinate(self.targetLocation.coordinate));
}
// From: http://stackoverflow.com/questions/3925942/cllocation-category-for-calculating-bearing-w-haversine-function
double DegreesToRadians(double degrees) {return degrees * M_PI / 180.0;};
double RadiansToDegrees(double radians) {return radians * 180.0/M_PI;};
/// Calculate the bearing between two points
-(double) bearingToLocation:(CLLocation *) destinationLocation fromLocation:(CLLocation *) fromLocation {
double lat1 = DegreesToRadians(fromLocation.coordinate.latitude);
double lon1 = DegreesToRadians(fromLocation.coordinate.longitude);
double lat2 = DegreesToRadians(destinationLocation.coordinate.latitude);
double lon2 = DegreesToRadians(destinationLocation.coordinate.longitude);
double dLon = lon2 - lon1;
double y = sin(dLon) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
double radiansBearing = atan2(y, x);
if(radiansBearing < 0.0)
radiansBearing += 2*M_PI;
return RadiansToDegrees(radiansBearing);
}
// ******************** Pointer View ********************
#pragma mark - Pointer View
- (void) hidePointerViews {
self.northPointerView.hidden =
self.southPointerView.hidden =
self.eastPointerView.hidden =
self.westPointerView.hidden = YES;
}
- (void) showCardinalPointDirection:(double) bearing {
CardinalPoint point = [self cardinalPointWithBearing:bearing];
// Determine which pointer should be shown based on the bearing
UIView * activePointer;
switch (point) {
case North:
activePointer = self.northPointerView;
break;
case South:
activePointer = self.southPointerView;
break;
case East:
activePointer = self.eastPointerView;
break;
case West:
activePointer = self.westPointerView;
break;
}
// Rotate the pointer to show the bearing
activePointer.transform = CGAffineTransformMakeRotation(DegreesToRadians(bearing));
// Hide all pointers except the pertinent one
[self hidePointerViews];
activePointer.hidden = NO;
}
/// Returns the cardinal point for a given bearing (in Degrees)
- (CardinalPoint) cardinalPointWithBearing:(double) bearing {
if (bearing > 45.0 && bearing <= 135.0) {
return East;
} else if (bearing > 135.0 && bearing <= 225.0) {
return South;
} else if (bearing > 225.0 && bearing <= 315.0) {
return West;
} else {
return North;
}
}
#end
Additionally, the pointer rotation is based on the bearing between the userLocation and the targetLocation. It feels a little strange. Probably better to make the rotation based off of some other point. Maybe the center of the visible region at that moment...
I have been trying to solve this for many hours. None of the posts I have found anywhere has provided a solution. The problem is the textField is in a subview and I cannot figure out how to make it respond to the Return button to hide the keyboard.
Here is my view controller;
#import <UIKit/UIKit.h>
#import "Combatant.h"
#interface ViewController : UIViewController <CombatantDelegate>
- (IBAction) addView;
- (IBAction) roll;
#end
#import "ViewController.h"
static int startY = 60;
#interface ViewController ()
{
NSMutableArray * customViews;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
customViews = [[NSMutableArray alloc] init];
}
- (IBAction) addView
{
Combatant * thing = [[NSBundle mainBundle] loadNibNamed:#"Combatant" owner:nil options:nil][0];
[self.view addSubview: thing];
thing.center = CGPointMake(self.view.center.x, startY + customViews.count * thing.bounds.size.height);
thing.combatDelegate = self;
[customViews addObject:thing];
}
- (IBAction) roll
{
for (Combatant * cust in customViews)
{
[cust rollWasTapped];
}
}
#end
Here is my custom Class;
#import <UIKit/UIKit.h>
#class Combatant;
#protocol CombatantDelegate <NSObject>
#end
#interface Combatant : UIView <UITextFieldDelegate>
{
IBOutlet UITextField * name;
IBOutlet UITextField * base;
IBOutlet UITextField * die;
IBOutlet UITextField * mod;
IBOutlet UILabel * total;
NSString *value;
int dRoll;
int cBase;
int cMod;
}
#property (nonatomic, strong, readwrite) NSString *value;
#property (nonatomic, strong) IBOutlet UITextField * name;
#property (nonatomic, strong) IBOutlet UITextField * base;
#property (nonatomic, strong) IBOutlet UITextField * die;
#property (nonatomic, strong) IBOutlet UITextField * mod;
#property (nonatomic) IBOutlet UILabel * total;
-(void) rollWasTapped;
-(BOOL) textFieldShouldReturn:(UITextField *)textField;
#property (nonatomic, weak) id<CombatantDelegate> combatDelegate;
-(int) dieRoll;
-(int) convertBase;
-(int) convertMod;
#end
#import "Combatant.h"
#implementation Combatant
#synthesize value;
#synthesize name;
#synthesize base;
#synthesize die;
#synthesize mod;
#synthesize total;
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
}
return self;
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[name resignFirstResponder];
return YES;
}
- (void) rollWasTapped;
{
int tot;
tot = [self convertBase] + [self dieRoll] + [self convertMod];
total.text = [NSString stringWithFormat:#"%i", tot];
NSLog(#" totaling %i ", tot);
}
-(int) dieRoll
{
int val = [die.text intValue];
if (val <7 && val >0)
{
NSLog(#" %i die", val);
} else {
NSLog(#" there are no dice");
val = 0; }
int d = 0;
for (int i = 0; i < val; i++) {
d = d + arc4random()%6 + 1;
}
dRoll = d;
NSLog(#"%i die roll result = %i ", val, dRoll);
return dRoll;
}
-(int) convertBase
{
cBase = [base.text intValue];
NSLog(#"base = %i", cBase);
if (cBase > -1 && cBase < 20)
{
return cBase;
}
return 0;
}
-(int) convertMod
{
cMod = [mod.text intValue];
NSLog(#"mod = %i", cMod);
if (cMod > -20 && cMod < 20)
{
return cMod;
}
return 0;
}
- (void) dealloc
{
self.combatDelegate = nil;
}
#end
The code works perfect in every aspect except the keyboard hiding.
In the most basic sense, you want the currently active text field to resignFirstResponder. Your problem seems to be how to access that text field.
edit: the below paragraphs jump topics quickly, as I'm detailing a few possible solutions instead of 1.
Goal: Accessing the Text field.
Solutions:
1) Create a property that exposes the text field on the custom class.
2) Create a function that calls the text field on the custom class.
You have 4 properties exposing the text fields, assuming there are 4 text fields on each view?
In that case, go with creating a function, and in that function, on the view, make sure it calls self.textField1 resign... blah, then self.textField2, just make sure it hits all of them.
Currently you call name resignFirstResponder in the callback. But first let's backtrace a little bit. All textFields call textFieldShouldReturn on their delegate. So make sure all 4 of your text fields have the view as the delegate. Either in interface builder or code, self.name.delegate (or self.name.textFieldDelegate, I forgot exactly) = self; for each one.
Also, remember to call "self.", "name" is something else. Actually self. accesses the property accessor. But the invisible variable it creates is called _name (same thing with an underscore at the beginning, this works for all properties).
Now that we know all your fields are being called correctly, let's get back to the delegate. If you really do want the "currently active, returning" text field to resign its responder, the delegate passes in its object view the textField, so just remember to call resignFirst... on the currently returning field.
[textField resignFirstResponder]
Of course, that belongs in the delegate callback method, since textField does not exist otherwise, lest you access it by its name (self.name, or the others).
Last but not least, put a button behind everything, but large enough to cover the screen, make it call a function. In that function, you can "splay" the call to every text field. Basically, make that function call the "hideTheKeyboard" or whatever you named it (the function that calls resignFirst... on all the fields within the custom view) on every custom view.
It should look like your function with for( view in customViews) but instead of calling roll, it calls your custom function.
Within that function, just because it is a possible solution, you can also do something like
- (IBAction) roll
{
for (Combatant * cust in customViews)
{
[cust.name resignFirstResponder];
[cust.die resignFirstResponder];
// and on for the other 2
}
}
But, as you can tell, the reason you might want that encapsulated into a function that you call is simply for less lines of code/simplicity. It is more important that you understand how and why you can do it either way than finding a solution that works. There are 3 solutions I've listed above (use a property, use a function to access the textField, or use the delegate).
The simplest is the delegate, the most compact is the function, and the most widespread is the property. (There are also limitations to each one). I wanted to give a thorough understanding so you can see them.
Put it in the textFieldDidEndEditing: method
- (void)textFieldDidEndEditing:(UITextField *)textField {
{
[textField resignFirstResponder];
}
In viewDidLoad add this:
name.delegate = self;
Or you can do this in the storyboard in the Connections Inspector, by dragging delegate outlet to your view controller.
PS: In this case, textFieldShouldReturn method should be in the view controller too.
You are using delegate which describes that if it should return or not? and before even you are returning you are sending event to your text field keyboard to return or dismiss which is not possible. please try the code as per mentioned by #soulshined.
- (void)textFieldDidEndEditing:(UITextField *)textField {
{
[textField resignFirstResponder];
}
I'm trying to put together a simple compass for iOS. The rotation animation seems to rotate the compass image around the center of the screen so I am trying to automatically center the UIImageView of compass Image so that it will work on different devices.
And this is where my problem is. I have attempted to center the image with the following code within ViewDidLoad but with no result:
compassImage.center = CGPointMake(CGRectGetMidX(self.view.frame), CGRectGetMidY(self.view.frame));
I have originally placed the compass image in a random place within the Storyboard just to make sure this works. I have printed NSLog checks before and after this centering code to make sure that it is having and effect and it does seem to be centering the image (on my iPhone 4s) yet this is not reflected in the view:
2014-05-17 12:18:23.015 Compass[447:60b] Old: 160, 386
2014-05-17 12:18:23.019 Compass[447:60b] New: 160, 240
I'd post an image but am not allowed as it is my first post.
In fact heres the whole setup. I'm sure I've gone wrong somewhere:
ViewController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <QuartzCore/QuartzCore.h>
#interface ViewController : UIViewController <CLLocationManagerDelegate>
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) IBOutlet UIImageView *compassImage;
#property (nonatomic, retain) IBOutlet UILabel *trueHeadingLabel;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController()
#end
#implementation ViewController
#synthesize locationManager, compassImage, trueHeadingLabel;
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Old: %i, %i", (int)compassImage.center.x, (int)compassImage.center.y);
compassImage.center = CGPointMake(CGRectGetMidX(self.view.frame), CGRectGetMidY(self.view.frame));
NSLog(#"New: %i, %i", (int)compassImage.center.x, (int)compassImage.center.y);
locationManager=[[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.headingFilter = 1;
locationManager.delegate=self;
// Start the compass updates
[locationManager startUpdatingHeading];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
// Convert Degree to Radian
// Multiply by -1 to twist opposite to phone rotation
float oldRad = -manager.heading.trueHeading * M_PI / 180.0f;
float newRad = -newHeading.trueHeading * M_PI / 180.0f;
// creating needle spin animation
CABasicAnimation *theAnimation;
theAnimation=[CABasicAnimation animationWithKeyPath:#"transform.rotation"];
theAnimation.fromValue = [NSNumber numberWithFloat:oldRad];
theAnimation.toValue=[NSNumber numberWithFloat:newRad];
theAnimation.duration = 0.5f;
// applying the animation
[compassImage.layer addAnimation:theAnimation forKey:#"animateMyRotation"];
compassImage.transform = CGAffineTransformMakeRotation(newRad);
// setting labels to heading
trueHeadingLabel.text = [NSString stringWithFormat:#"%i°", (int)(newHeading.trueHeading)];
// console print of heading
NSLog(#"True heading: %f", newHeading.trueHeading);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
I have looked at pretty much every question and answer on here with anything to do with changing the position of a UIImageView and centering and nothing is doing the job. I get the feeling that it could just be the way I'm setting up the whole program and this wouldn't be a surprise since I am a new and super-inexperienced. Any help would be fantastic. Even advice on better programming practice too. If you need any more information gimmie a shout.
Sounds like you may have autolayout enabled and that overrides your code.
Change:
compassImage.center = CGPointMake(CGRectGetMidX(self.view.frame), CGRectGetMidY(self.view.frame));
To:
compassImage.center = self.view.center;
Also, make sure that you have no constraints on the compassImage in IB that would interfere.
I'm currently having a very strange bug with regard to a CALayer subclass. This CALayer subclass is responsible for drawing a UI element, and is contained inside of a custom UIView class. When the UIView receives touch events, it changes the UIElementLayer's properties, causing the layer to be redrawn.
However, the weird problem that I'm having is that occasionally the layer will freeze up. When I say freeze up, I mean that drawInContext() does not get called until the first second of the next minute. Literally every time it freezes up, I can count on it going back to normal at the :00 component of the next minute. I have tried debugging all of my functions, and I just can't find a reason why this is happening. Any ideas on what could be causing this?
The details of that class are:
#interface UIElementLayer : CALayer
#property (nonatomic) CGFloat beginningValue;
#property (nonatomic) CGFloat endingValue;
#property (nonatomic) BOOL shouldReset;
#end
#implementation UIElementLayer
#dynamic beginningValue, endingValue, shouldReset;
- (id)initWithLayer:(id)layer
{
if (self = [super initWithLayer:layer])
{
if ([layer isKindOfClass:[UIElement class]])
{
UIElement *element = (UIElement *)layer;
self.shouldReset = element.shouldReset;
self.startingValue = element.startingValue;
self.endingValue = element.endingValue;
}
}
return self;
}
+ (BOOL)needsDisplayForKey:(NSString *)key
{
if ([key isEqualToString:#"startingValue"] ||
[key isEqualToString:#"endingValue"]
|| [key isEqualToString:#"shouldReset"])
{
return YES;
}
return [super needsDisplayForKey:key];
}
i try to set a value to a slider after a button click,
but it does not work - the slider does not move. the code runs fine without mistakes.
It should be pretty simple but I can't figure it out.
xCode Version 4.5.2
Thanks!
here my code:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *debugLabel;
#property (weak, nonatomic) IBOutlet UISlider *slider;
- (IBAction)slider:(id)sender;
- (IBAction)ButtonChangeValue:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize slider;
...
- (IBAction)slider:(UISlider *)sender {
float value = [sender value];
self.debugLabel.text = [NSString stringWithFormat:#"Value: %f",value];
}
- (IBAction)ButtonChangeValue:(id)sender {
slider.value = 90;
}
I think your problem is that the slider accepts values between 0.0 and 1.0 (default values, change them with _slider.maximumValue and _slider.minimumValue). Try setting the value to 0.9 instead of setting 90 (if you mean 90%).
If the slider updates but is not animated, use :
[_slider setValue:0.9 animated:YES];
Note that given your code, you may need to use self.slider instead of _slider.
try using
self.slider.value = 90;
instead of
slider.value = 90;
Check My Answer
- (void)viewDidLoad
{
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(sliderTapped:)];
[slider addGestureRecognizer:gr];
}
- (void)sliderTapped:(UIGestureRecognizer *)g
{
UISlider* s = (UISlider*)g.view;
if (s.highlighted)
return; // tap on thumb, let slider deal with it
CGPoint pt = [g locationInView: s];
CGFloat percentage = pt.x / s.bounds.size.width;
CGFloat delta = percentage * (s.maximumValue - s.minimumValue);
CGFloat value = s.minimumValue + delta;
[s setValue:value animated:YES];
NSString *str=[NSString stringWithFormat:#"%.f",[self.slider value]];
self.lbl.text=str;
}
To use slider.value = 90;
Your ViewController.h should be:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
UISlider *slider;
}
#property (weak, nonatomic) IBOutlet UILabel *debugLabel;
#property (weak, nonatomic) IBOutlet UISlider *slider;
- (IBAction)slider:(id)sender;
- (IBAction)ButtonChangeValue:(id)sender;
#end
And don't forget #synthesize slider; in your ViewController.m as well.
Otherwise, use self.slider.value = 90; or _slider.value = 90;
For Swift, you can use:
slider.setValue(5.0, animated: true)
Since you are using interface builder first thing to look at would be: are the UI components (slider, button) connected to the IBOutlets in File's owner. This is the most common source of problems like this.
Then check the min and max of the slider (default is 0;1 - as rdurand mentioned).
And spider1983 is correct also: since slider is a property, you can address it as self.slider (or _slider, but you shouldn't use the last one in this case).
i think . as you have not mentioned maximum and minimum value of slider ,it is taking default max and min values that are 0 to 1. So it is not possible to set value =90. First change its max and min like this :
Slider.minimumValue = 1;
Slider.maximumValue = 100;
now try your thing ,
Slider.value =90;
Within view
#State private var value1: Double = 0.9
Then make reference
Slider(value: $value1)