Getting negative value when UISlider goes left - ios

I was trying to figure out how to get a negative value of the slider when it goes back.
When I slide from left to right it returns a positive value. I need it to return a negative value when it goes back (from right to left).
In other words, how could I detect that the slider is going back?
self.borderSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 200, 30)];
self.borderSlider.center = CGPointMake(self.view.centerX, SCREEN_WIDTH / 2);
self.borderSlider.minimumValue = 0.0f;
self.borderSlider.maximumValue = 100.0f;
self.borderSlider.tintColor = [UIColor grayColor];
[self.borderSlider addTarget:self action:#selector(borderSliderValueChanged:) forControlEvents:UIControlEventValueChanged];

A simple example expressing what #rmaddy already stated in his comment:
#implementation YourClass {
float _sliderValue;
}
- (void)borderSliderValueChanged:(UISlider *)slider {
float currentValue = slider.value;
if (currentValue > _sliderValue) {
// right
} else if (currentValue < _sliderValue) {
// left
}
_sliderValue = currentValue;
}
#end

I had the same problem so I've developed it, check this repo: Repo
slider?.amplitude = 50
slider?.sliderDidChange = { [weak slider] value in
if value > 10 {
slider?.activeColor = .blue
} else if value < 0 {
slider?.activeColor = .red
} else {
slider?.activeColor = .lightGray
}
}

Related

CGFloat MinimumValue vs CurrentValue

I created a custom slider with a uiview class ... everything works fine but I just have a problem ...
in my view controller implements the Custom Slider class this way
Main ViewController
#pragma mark SMALL STATS
-(KPStatsSlider *)statsSlider {
if (!_statsSlider) {
_statsSlider = [[KPStatsSlider alloc] init];
_statsSlider.minimumValue = 18;
_statsSlider.maximumValue = 30;
_statsSlider.currentValue = 12;
_statsSlider.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.statsSlider];
[self.statsSlider.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:115].active = YES;
[self.statsSlider.rightAnchor constraintEqualToAnchor:self.view.rightAnchor constant:0].active = YES;
[self.statsSlider.heightAnchor constraintEqualToConstant:70].active = YES;
[self.statsSlider.leftAnchor constraintEqualToAnchor:self.view.centerXAnchor constant:0].active = YES;
}
return _statsSlider;
}
as you can see, I can assign the value:
Current /
Minimum /
Maximum
In my personalized UIView I implemented this feature to prevent the CurrentValue value being smaller than MinimumValue but I can not get it running can you help me with this?
Custom Slider UIView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
[self defaultValue];
[self setupStatsTitle];
[self trackLine];
if (self.currentValue <= self.minimumValue) {
self.currentValue = self.minimumValue;
}
}
return self;
}
Seems like you want
if (self.currentValue <= self.minimumValue) {
self.currentValue = self.minimumValue;
}
In the setter of currentValue. For example:
- (void)setCurrentValue:(CGFloat)currentValue {
_currentValue = currentValue;
if (_currentValue < self.minimumValue) {
_currentValue = self.minimumValue;
}
if (_currentValue > self.maximumValue) {
_currentValue = self.maximumValue
}
}
Your code currently only checks when the slider is initialized, but not if currentValue is set later.
In general, I prefer to access an instance variable directly if I’m in that instance variable’s setter/getter to avoid confusion and possible infinite recursion, but your code as written is okay.

Using Masonry to Layout 9 points

I'm using Masonay to layout UI like this:
UI requirement
The size of the 9 points are the same.
And the margin between 9 points are the same.
My question is that how to make margin to left of first column point equal to the margin to the right of the last column points by using Masonay ?
My code blow is not complete.
Can anyone help me with this?
for (NSInteger i = 0; i < 9; i++) {
NSInteger row = i / 3;
NSInteger column = i % 3;
UIView * previousRowPoint;
UIView * previousColumnPoint;
UIView * firstPoint;
if (row > 0) {
previousRowPoint = hintPoints[(row - 1) * 3];
}
if (column > 0) {
previousColumnPoint = hintPoints[column - 1];
}
if (0 != i) {
firstPoint = hintPoints[0];
}
UIView * hintPoint = [[UIView alloc] init];
[hintPoints addObject:hintPoint];
hintPoint.layer.cornerRadius = 8 / 2;
hintPoint.layer.masksToBounds = YES;
hintPoint.layer.borderColor = [UIColor grayColor].CGColor;
hintPoint.layer.borderWidth = 0.5;
[self.view addSubview:hintPoint];
hintPoint.mas_key = [NSString stringWithFormat:#"hintPoint_%ld", (long)i];
[hintPoint mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(8);
make.height.mas_equalTo(8);
if (row == 0) {
make.top.equalTo(weakself.view).offset(100);
}
else {
make.top.equalTo(previousRowPoint.mas_bottom).offset(4);
}
if (column == 0) {
//TODO: how to make the trailing equal to the first point's leading
}
else if (column == 2) {
//TODO: how to make the trailing equal to the first point's leading
}
else {
make.leading.equalTo(previousColumnPoint.mas_trailing).offset(4);
}
}];
}

Is there a way to shuffle/rearrange buttons on an iOS application?

I am developing an iOS application. I have 35 buttons on the storyboard. Is there anyway I can use a random generator to randomly rearrange or shuffle the buttons and still maintain the button's functionality?
You can add all the button objects to an NSMutableArray called buttonsArray and then use the following loop to exchange the buttons:
for (int i = 0; i < buttonsArray.count; i++) {
int random1 = arc4random() % [buttonsArray count];
int random2 = arc4random() % [buttonsArray count];
[buttonsArray exchangeObjectAtIndex:random1 withObjectAtIndex:random2];
}
If each of the button is belongs to a class like below then its really easy to shuffle them,
MyRandomButton {
NSInteger uniqueId;
NSString *title;
....
....
}
Now, what you can do is, at initial, prepare number of objets of MyRandomButton (equals to count of buttons on your StoryBoard). And add it into a mutable array (NSMutableArray).
Like this,
for(NSInteger index = 1; index <= 35; index++) {
MyRandomButton *btnInfo = ...;
btnInfo.uniqueId = index;
btnInfo.title = #sometitle;
[myButtonsArray addObject:btnInfo];
}
In next step, if you're done with something (and you want to shuffle all buttons) then get help from this question, What's the Best Way to Shuffle an NSMutableArray? to shuffle your array.
Loop through all buttons on your StoryBoard (in your case: 1 to 35).
for(NSInteger index = 1; index <= 35; index++) {
UIButton *button = (UIButton *)[yourView viewWithTag:index];
MyRandomButton *btnInfo = [myButtonsArray objectAtIndex:(index-1)];
button.tag = btnInfo.uniqueId;
[button setTitle:btnInfo.title forState:UIControlStateNormal];
}
Inside above loop, we've updated buttons title and tag.
Done!
That is possible, it will require some coding:
Create NSMutableArray with all buttons of the view in it.
Randomize its order.
Run over the buttons array and on each iteration keep last
button view and switch its rect with current button and
vice versa.
For better understanding, here is the code (ready for use, just copy paste):
- (void)viewDidLoad {
[super viewDidLoad];
// Getting buttons into array
NSMutableArray * buttonsArr = [self getButtonsArray];
// Shuffling buttons location
if(buttonsArr && [buttonsArr count]) {
[self randomizeButtonsLocation:buttonsArr];
} else {
NSLog(#"No buttons found");
}
}
- (void)randomizeButtonsLocation:(NSMutableArray *)buttonsArr {
// Randomizing order in button array
buttonsArr = [self randomizeArr:buttonsArr];
UIButton * lastBtn = nil;
for (UIButton * btn in buttonsArr) {
if(!lastBtn) {
lastBtn = btn;
} else {
// Put a side frames of last and current buttons
CGRect lastBtnRect = [lastBtn frame];
CGRect currentBtnRect = [btn frame];
// Switch frames
[btn setFrame:lastBtnRect];
[lastBtn setFrame:currentBtnRect];
// Keeping last btn for next iteration
lastBtn = btn;
}
}
}
- (NSMutableArray *)getButtonsArray {
// Getting all buttons in self.view and inserting them into a mutable array
NSMutableArray * resultArr = [[NSMutableArray alloc] init];
for (UIButton * btn in [self.view subviews]) {
if([btn isKindOfClass:[UIButton class]]) {
[resultArr addObject:btn];
}
}
return resultArr;
}
- (NSMutableArray *)randomizeArr:(NSMutableArray *)arr {
NSUInteger count = [arr count];
for (NSUInteger i = 0; i < count; ++i) {
unsigned long nElements = count - i;
unsigned long n = (arc4random() % nElements) + i;
[arr exchangeObjectAtIndex:i withObjectAtIndex:n];
}
return arr;
}
For anyone who needs to do this in SWIFT, here's how:
func randomlyPositionAnswerButtons() {
var posX = CGFloat()
var posY_button1 = CGFloat()
var posY_button2 = CGFloat()
var posY_button3 = CGFloat()
// if self.view.frame.size.height == 667 { /* ======== IPHONE 7, 7S, 8 ======== */
posX = 24 // Set all buttons to start from 37
posY_button1 = 310
posY_button2 = 405
posY_button3 = 500
// }
let tab = [
[1,2], [0,2], [0,1]
]
let indexArray = [
NSValue(cgRect:CGRect(x: posX, y: posY_button1, width: 350, height: 74)),
NSValue(cgRect:CGRect(x: posX, y: posY_button2, width: 350, height: 74)),
NSValue(cgRect:CGRect(x: posX, y: posY_button3, width: 350, height: 74))
] as NSMutableArray
// Shuffle the array
var p = UInt32()
p = arc4random() % 3
indexArray.exchangeObject(at: 0, withObjectAt: Int(p))
indexArray.exchangeObject(at: tab[Int(p)][0], withObjectAt: tab[Int(p)][1])
// Assign the buttons their new position
optionButtonA.frame = (indexArray[0] as AnyObject).cgRectValue
optionButtonB.frame = (indexArray[1] as AnyObject).cgRectValue
optionButtonC.frame = (indexArray[2] as AnyObject).cgRectValue
}
Rearranging the fixed buttons sounds like a headache, if only in terms of autolayout constraints.
Why don't you:
Create and position 35 "generic" buttons on the storyboard, each with their own outlet (properties named button01, button02, etc.), or better: use an outlet collection?
Assign a unique tag to each button (0, 1, 2, 3...) on the storyboard.
Assign the same #IBAction method to all your buttons on the storyboard.
At runtime, determine and assign a specific "role" to each button at random (and set each button's label accordingly). But keep track of which button is which, using -for example- a dictionary.
The action linked to all buttons will use the tag of the sender and the information contained in the dictionary mentioned above to determine which "role" button was tapped, and act accordingly.
Does it make sense?

getting the contents of UIButton press

I'm not sure if this has been asked before, but I'm gonna ask anyways. I am working on a grid of buttons, with letters as the titles of each one. I am getting the contents of these letters from an array, and I believe that is where my issue is coming from. The titles appear just fine, but when I press on any of the buttons in my array, that is where my issue comes in.
Every time I press a letter, the part of my NSLog NSLog(#"Letter Added to Array: %#", self.sectionButton.titleLabel.text);
displays
Letter Added to Array: S
and that is all that is displayed. No matter what button is pushed. I am thinking it might just be because of S being the last object in my array, which is why it's saying that. I don't know, so ANY help would be appreciated.
Here is my code:
- (void) didTouchButton
{
[self.lettersPressedArray addObject:self.sectionButton.titleLabel.text];
NSLog(#"Letter Added to Array: %#", self.sectionButton.titleLabel.text);
NSLog(#"Letters Pressed = %#", self.lettersPressedArray);
}
- (void)showGridWithRows:(int)r columns:(int)c arrayOfContent:(NSArray *)content withSizeOfContent:(CGFloat)contentSize
{
for (int i = 0; i < content.count; i++) {
// vars
int row = (int)i / r; // to figure out the rows
int col = i % c; // to figure out the columns
float x = 0;
float y = 0;
// sizing options
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
CGSize screen = [UIScreen mainScreen].bounds.size;
if (screen.height == 480) {
x = 1 + (40 * col);
y = 1 + (30 * row);
}
else {
x = 2 + (40 * col);
y = 1 + (31 * row);
}
}
else {
x = .5 + (90 * col);
y = 1 + (90 * row);
}
//button
self.sectionButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.sectionButton setTintColor:[UIColor lightGrayColor]];
self.sectionButton.frame = CGRectMake(x, y, contentSize, contentSize);
self.sectionButton.tag = 100 + row * c + col;
[self.sectionButton addTarget:self action:#selector(didTouchButton) forControlEvents:UIControlEventTouchUpInside];
// font stuff
self.sectionButton.titleLabel.textAlignment = NSTextAlignmentCenter;
self.sectionButton.titleLabel.backgroundColor = [UIColor clearColor];
self.sectionButton.titleLabel.font = [UIFont fontWithName:#"Helvetica-Light" size:22];
[self.sectionButton setTitleColor:[UIColor blackColor]/*[UIColor colorWithRed:241.0/255.0 green:124.0/255.0 blue:22.0/255.0 alpha:1.0]*/ forState:UIControlStateNormal];
// title
s = (NSString *)[content objectAtIndex:i];
[self.sectionButton setTitle:s forState:UIControlStateNormal];
// color
if ([s isEqualToString:#"A"] ) {
[self.sectionButton setBackgroundColor:[UIColor greenColor]];
}
else if([s isEqualToString:#"Z"]) {
[self.sectionButton setBackgroundColor:[UIColor redColor]];
}
else {
[self.sectionButton setBackgroundColor:[UIColor lightGrayColor]];
}
//layer
self.sectionButton.layer.borderWidth = .65;
//self.sectionButton.layer.cornerRadius = 5.0;
for(int j = 0; j < c; j++) {
for (int k = 0; k < r; k++) {
[self addSubview:self.sectionButton];
}
}
}
}
Change this:
- (void) didTouchButton
{
[self.lettersPressedArray addObject:self.sectionButton.titleLabel.text];
NSLog(#"Letter Added to Array: %#", self.sectionButton.titleLabel.text);
NSLog(#"Letters Pressed = %#", self.lettersPressedArray);
}
To this:
- (void) didTouchButton:(UIButton *)sender
{
[self.lettersPressedArray addObject:sender.titleLabel.text];
NSLog(#"Letter Added to Array: %#", sender.titleLabel.text);
NSLog(#"Letters Pressed = %#", self.lettersPressedArray);
}
And when you assign your button selector add a ':'
So, this:
#selector(didTouchButton)
Will be:
#selector(didTouchButton:)
Probably implemented like:
[someButton addTarget:self action:#selector(didTouchButton:) forControlEvents:UIControlEventTouchUpInside];
Because:
The way you originally reference your button via self.selectionButton.titleLabel.text accesses one specific instance of a button. This means that no matter what button triggers didTouchButton it gets the content of self.selectionButton which I'm assuming displays an "S". This means that no matter what happens, you add more of the letter "S" to your array. By configuring our action method like we did, it will pass "self" as an argument. This means that we have a variable representing whoever called the method within the method. We will use that to get our contents and add them to the array.
Couple things here. Firstly, you likely don't want to have the button be a property, because you are constantly overwriting it and are ultimately left with it referencing the last one you created... What you're basically doing is the same as:
int x = 1;
x = 2;
x = 3;
printing x will ALWAYS result in 3... Make sense?
The solution to your problem is to pass the button you are tapping as a parameter to the function that handles the action, by adding in a ":" after "didTouchButton" and changing the way you create that function. When you create the button, add the : after the function name like this:
[button addTarget:self action:#selector(didTouchButton:) forControlEvents:UIControlEventTouchUpInside];
That allows a reference to the button pressed to be passed to the function, so you can do this to handle it:
- (void)didTouchButton:(UIButton *)button {
NSString *titleOfPressedButton = button.titleLabel.text;
}
You need to change didTouchButton method to accept (id)sender parameter and change how you set up it's selector while creating a button to didTouchButton:.
This way you will receive a button object pointer inside the didTouchButton and will be able to get its information.

transform image when it hits the edge of the screen in iOS

I have 10 fireflies that I make "fly" around the screen using the code below.
The code also serves to keep the fireflies on the screen.
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *blueArray = [NSArray array];
blueArray = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:#"blue1.png"],
[UIImage imageNamed:#"blue2.png"], nil];
blue.animationImages = blueArray;
blue.animationDuration = 0.20;
blue.animationRepeatCount = -1;
[blue startAnimating];
bluepos =CGPointMake(2.0, 1.5);
}
-(void) someMethod {
endingAnimationTimer = [NSTimer scheduledTimerWithTimeInterval:(0.03) target:self selector:#selector(makeFly) userInfo:nil repeats:YES];
}
-(void) makeFly {
blue.center = CGPointMake(blue.center.x+bluepos.x, blue.center.y+bluepos.y);{
if(blue.center.x > 480 || blue.center.x <0)
bluepos.x = -bluepos.x;
if(blue.center.y > 320 || blue.center.y <0)
bluepos.y = -bluepos.y;
}
}
The "flying" works great except that when the fireflies hit the edge of the screen and reverse direction to keep them on the screen the firefly image itself is still "facing" the othe direction so it looks like they are flying backwards half the time.
I want to set it up so that when the fireflies hit the edge of the screen they reverse direction AND the image itself is reversed.
I tried this:
In .h
#property (nonatomic, assign) BOOL blueIsFacingRight;
In .m
#synthesize blueIsFacingRight;
-(void) makeFly {
blue.center = CGPointMake(blue.center.x+bluepos.x, blue.center.y+bluepos.y); {
if(blue.center.x > 480 ) {
if (blueIsFacingRight == YES) {
blue.transform = CGAffineTransformMakeScale(-1, 1);
blueIsFacingRight = NO;
}
bluepos.x = -bluepos.x;
}
if(blue.center.x <0) {
bluepos.x = -bluepos.x;
if (blueIsFacingRight == NO) {
blue.transform = CGAffineTransformMakeScale(1, 1);
blueIsFacingRight = YES;
}
}
if(blue.center.y > 320 )
bluepos.y = -bluepos.y;
if( blue.center.y <0)
bluepos.y = -bluepos.y;
}
}
I thought this would work but the image does not reverse when it hits the "wall"
Can anyone explain why this does not work and if there is a better why to accomplish the effect im looking for?
You are setting the transform X value to -1 in both cases. When its facing right you should set transform like this CGAffineTransformMakeScale(1, 1);
blue.center = CGPointMake(blue.center.x+bluepos.x, blue.center.y+bluepos.y); {
if(blue.center.x > 480 ) {
if (blueIsFacingRight == YES) {
blue.transform = CGAffineTransformMakeScale(-1, 1);
blueIsFacingRight = NO;
}
bluepos.x = -bluepos.x;
}
if(blue.center.x <0) {
bluepos.x = -bluepos.x;
if (blueIsFacingRight == NO) {
blue.transform = CGAffineTransformMakeScale(1, 1);
blueIsFacingRight = YES;
}
}
**blue.transform =CGAffineTransformIdentity;**
THe above was in my makeFly method with a bunch of other stuff above where I was reversing the image so I was undoing the change the very next time the method was called ( 0.03 later)
Man I feel stupid

Resources