(Swift, EarlGrey) move slider to the middle - ios

I'm writing some tests and I need to go to the middle of a slider. I would like to get minimumValue and maximumValue of the slider, like on a picture below:
These values may change so every time I need to get them in my code. Later, I just want to get average of these two values and move the slider to the middle using a method
performAction:grey_moveSliderToValue(valueToMove)
How can I get minumumValue and maximumValue in my code? Is this the best approach or is there any better to move playhead to the middle of the slider?

You can use EarlGrey's GREYActionBlock to create a new action that slides to half
// Create a new action that slides to half.
GREYActionBlock *slideToHalfAction = [GREYActionBlock actionWithName:#"slideToHalf"
constraints:grey_kindOfClass([UISlider class])
performBlock:^BOOL(id element, NSError *__strong *errorOrNil) {
UISlider *slider = element;
float minValue = slider.minimumValue;
float maxValue = slider.maximumValue;
float halfValue = (minValue + maxValue) / 2;
return [grey_moveSliderToValue(halfValue) perform:element error:errorOrNil];
}];
// Use the new action on the slider.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(#"slider4")] performAction:slideToHalfAction];

Related

Connecting slider to label

How can I connect the position of slider's value with label's position? I want, that when slider change its value, the label move with slider's value too. please help me. I can't write this code.
You need to add this inside the slider change value action
// calculate current space available for movement
let factor = ( self.view.frame.width - self.label.frame.width ) / maxSliderValue
// apply the change according to slider value assuming in x axis
self.label.frame.origin.x = factor * slider.value

Animate a custom property's value?

I can easily animate something like the position or size of a UIView. But how can I animate a "custom" variable (such as experiencePoints) to achieve interpolation of values that are not associated with a UIView.
// The variable being animated
CGFloat experiencePoints = 0;
// Pseudo-code
[experiencePoints animateTo:200 duration:2 timingFunction:someTimingFunction];
With this code, if I accessed experiencePoints while it was animating, I would get a value between 0 and 200 based on how long the animation has been going.
Bonus question: Is it possible to use a CAAnimation to do what I want?
You can go with Presentation layer with CADisplayLink and by adding observer on animation status you can increment the variable upto your final one. Observer will observe current status of Animation which will eventually provide you a way to get current value of that VAR.
Ended up using Facebook's POP animation library, which allows the animation of any property on an object. I recommend it!
Here is a quote from the readme, explaining how to do it:
The framework provides many common layer and view animatable properties out of box. You can animate a custom property by creating a new instance of the class. In this example, we declare a custom volume property:
prop = [POPAnimatableProperty propertyWithName:#"com.foo.radio.volume" initializer:^(POPMutableAnimatableProperty *prop) {
// read value
prop.readBlock = ^(id obj, CGFloat values[]) {
values[0] = [obj volume];
};
// write value
prop.writeBlock = ^(id obj, const CGFloat values[]) {
[obj setVolume:values[0]];
};
// dynamics threshold
prop.threshold = 0.01;
}];
anim.property = prop;
"Animating" something is simply moving a value from a starting position to an ending position over time. To "animate" a float from one value to another over a duration you could just run a timer and incrementally change it. Or possibly you could store the begin and end time of the "animation" and whenever the value is accessed, compare those to the actual time to come up with a value.

UISlider limitations in IPhone

In UISlider Control if I set "MinimumValue = 0" & "MaximimValue=2000" then I am not able to set the exact value. On release of slider thumb image it changes the value to + or - 5 to10. My slider width = 225px.
For example:- if I try to set the slider value to 100 then on release of slider thumb it shows me result like 105 or 95.
Code
IBOutlet UISlider * slider;
//"Slider" Object attached using XIB(.NIB)
slider.minimumValue = 0;
slider.maximumValue = 100;
//Attached Below Method Using XIB(.NIB) with "value Changed" event.
-(IBAction)slider_Change:(id)sender;
{
//Assigning value to UITextField
textFiled.text = [NSString stringWithFormat:#"%d",(((int) (slider.value)) * 20)];
}
Because you have set your slider range to be so large each pixel on the screen is equivalent to 8.888.
2000 / 255 = 8.8888888889
To get graduations of 1 you'll need to move the slider 1/8 of a pixel (this is impossible).
Alternatives are:
Make the slider longer
Reduce the slider range
Use a different control UIStepper
In addition to the answer by #rjstelling, it seems as if you are trying to convert the value of the slider to become an integer value. I believe that the default of the slider is a double value, this would cause the value to become rounded as it is increasing, since there will not be decimal values. Unless it is a requirement, see if you can use double.
textFiled.text = [NSString stringWithFormat:#"%f",(slider.value * 20.0)];
or if for some reason you'd want to restrict the level of decimal places you could go, you could do:
textField.text = [NSString stringWithFormat:#"%.1f", slider.value * 20.0];
This will give you the result of a decimal like 1.5 as your answer.
You could do anything with the decimal or even do something like %1.2f, %4.3f, or even %10.4f,
those will produce results like: 0.34, 0012.446, and something extreme like 000000345.1111
Hope this helps

iOS, trigger UIViewAnimation once at slider value n?

I have a set of sliders, I'm using Value Changed to feed a number to a % indicator. I'm also using this value to check if the slider is below a certain point. If it is, I want to run a UIViewAnimation (which I am, it's all working fine). However, the animation gets called constantly if the slider is moved below the threshold, meaning the items being animated go from point a to point b then back again over and over. So, can I trigger the animation once only at the threshold point?
This is how I get my value in pixels:
_sizeSliderRange = _sizeSlider.frame.size.width - _sizeSlider.currentThumbImage.size.width;
_sizeSliderOrigin = _sizeSlider.frame.origin.x + (_sizeSlider.currentThumbImage.size.width / 4.0);
_sizeSliderValueToPixels = (_sizeSlider.value * _sizeSliderRange) + _sizeSliderOrigin;
And I use a conditional inside the linked Value Changed IBAction function to checkt he value and do the work:
if (_sizeThumbX < 85) { //if within 60px of the left margin we animate the label to sit float left
[UIView transitionWithView:_sizeLabel duration:0.25f options:UIViewAnimationCurveEaseInOut animations:^(void) { etc etc
Thanks.
Like #Luis said, just use a BOOL property like this:
if (_sizeThumbX < 85) { //if within 60px of the left margin we animate the label to sit float left
if (!self.passedBelowThreshold) {
[UIView transitionWithView:_sizeLabel duration:0.25f options:UIViewAnimationCurveEaseInOut animations:^(void) { /* ... */ }
}
}
self.passedBelowThreshold = _sizeThumbX < 85;
Your code is working according to your logic that is everytime the slider value is changed and it is below 85 the animation will be invoked .You can have animation triggered only once in the follwing way :-
1>YOu can keep an absolute value at which animation occurs.Something like _sizeThumbX == 85
2>or you canhave counter of how many times the value changes . In a different function count and store the value of slider change.If the slider value lies in the 85 range do not increase the counter value and in your animation part check the counter flag and slider's current position if slider is still in below 85 range do not invoke animation if counter value is already 1 that is animation is already fired else invoke and increase the animation counter.
3>I am not ware of you conditions as you have not mentioned clearly but ithink you want to invoke the animation again if your slider goes beyond the range and comes back again , in that case make the count to zero (slider crosses the specified range) .

Bad to Set slider.value When User has Changed Slider Position?

In the online Stanford CS193p iPhone Application Development course, lecture 6, an application is built which has a slider as input and a custom view as output.
When the slider is changed, the view controller sets the slider value again.
Important bits of the view controller in Happiness 2.zip:
#implementation HappinessViewController
#synthesize happiness;
- (void)updateUI
{
// assignment-loop when called from happinessChanged:?
self.slider.value = self.happiness; // sets slider to model's (corrected) value
[self.faceView setNeedsDisplay];
}
- (void)setHappiness:(int)newHappiness
{
if (newHappiness < 0) newHappiness = 0; // limit value
if (newHappiness > 100) newHappiness = 100;
happiness = newHappiness;
[self updateUI]; // changed happiness should update view
}
- (IBAction)happinessChanged:(UISlider *)sender // called by changed slider
{
self.happiness = sender.value; // calls setter setHappiness:
}
Doesn't this result in a loop (slider changed -> model updated -> change slider -> ?)?
Or is this even good practice?
If the slider is updated from code, rather than by the user, it presumably doesn't sent the valueChanged action. So you don't get an infinite loop.
This can be used to "correct" the value selected by the user, or to force the slider onto regular tick marks instead of a smooth scale.

Resources