Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added snapping capability #17

Closed
appicus opened this issue May 7, 2014 · 8 comments
Closed

Added snapping capability #17

appicus opened this issue May 7, 2014 · 8 comments

Comments

@appicus
Copy link

appicus commented May 7, 2014

Hello again,

Sorry, I don't know how to commit my own enhancements, but I added a snapping capability to your project, this way:

In "ASValueTrackingSlider.h":

// ADD THESE TWO LINES
@property (nonatomic) float stepValue;
- (void)valueChanged;

In "ASValueTrackingSlider.m":

@interface ASValueTrackingSlider() <ASValuePopUpViewDelegate>

@property (strong, nonatomic) NSNumberFormatter *numberFormatter;
@property (strong, nonatomic) ASValuePopUpView *popUpView;
@property (nonatomic) BOOL popUpViewAlwaysOn; // (default is NO)
// THIS IS NEW:
@property (nonatomic) float lastQuestionStep;

@end

@implementation ASValueTrackingSlider
{
    CGSize _popUpViewSize;
    UIColor *_popUpViewColor;
    NSArray *_keyTimes;
    CGFloat _valueRange;
        // THIS IS NEW:
    float _lastQuestionStep;
}

 -(void)setup {
    // ...
    // THIS IS NEW
    if (0.0 == self.stepValue) self.stepValue = 1.0;
    _lastQuestionStep = (self.value) / self.stepValue;
    // ...
}

// ADD ALSO THIS METHOD
- (void)valueChanged {
  if (0.0 == self.stepValue) self.stepValue = 1.0;
  float newStep = roundf((self.value) / self.stepValue);
  self.value = newStep * self.stepValue;
}

valueChanged must be called from UITableViewController when the slider changes its value ( connect an action from slider in storyboard for Value Changed and name it sliderValueChanged)

In your UITableViewController class:

- (IBAction)sliderValueChanged:(id)sender {
  [self.slider valueChanged];
}

In viewDidLoad of your UITableViewController

- (void)viewDidLoad {
  [super viewDidLoad]
  // ...
  self.slider.minimumValue = 0.0;
  self.slider.maximumValue = 4.0;
  //THIS IS NEW:
  self.slider.stepValue = 1.0;
}

Greetings from Berlin
Kenan.

@appicus
Copy link
Author

appicus commented May 7, 2014

P.S. Small mistake... If "stepValue" is not set in viewDidLoad:

In from "UITableViewController" derived class:

- (void)viewDidLoad {
  [super viewDidLoad]
  // ...
  self.slider.minimumValue = 0.0;
  self.slider.maximumValue = 4.0;
  // self.slider.stepValue = 1.0; // <--- Not set
  // ...
}

In "ASValueTrackingSlider.m":

- (void)setup {
    _stepValue = 0.0;
    _lastQuestionStep = self.value;
    // ...
}

- (void)valueChanged {
  float newStep = 0.0;
  if (0.0 == self.stepValue) {
    newStep = self.value;
  } else {
    newStep = roundf((self.value) / self.stepValue);
    self.value = newStep * self.stepValue;
  }
}

Appicus.

@alskipp
Copy link
Owner

alskipp commented May 7, 2014

Hi @appicus, thanks for your contribution. I'm wondering whether there is a simpler way of achieving the same objective? Let's assume there's a slider with minimumValue = 0 and maximumValue = 4 and we want the slider ‘thumb’ to always snap to integer values. This should be possible in the controller with the following method:

// connect this action to 'Touch Up Inside' in the Storyboard
- (IBAction)snapValue:(UISlider *)slider
{
    [slider setValue:lroundf(slider.value) animated:YES];
}

If custom labels need to be displayed for the 5 slider values, something like this should work:

- (void)viewDidLoad
{ 
    self.popUpLabels = @[@"A", @"B", @"C", @"D", @"E"];
    self.slider.minimumValue = 0;
    self.slider.maximumValue = 4;
}

// WARNING: this dataSource method doesn't exist yet!!!
- (NSString *)progressView:(ASProgressPopUpView *)progressView stringForValue:(float)value;
{
    NSUInteger i = lroundf(value);
    return self.popUpLabels[i];
}

Let me know if this is useful, or if I have misunderstood the problem.

Cheers,
Al

@appicus
Copy link
Author

appicus commented May 7, 2014

I've tried your suggestion with:

// connect this action to 'Touch Up Inside' in the Storyboard
- (IBAction)snapValue:(UISlider *)slider
{
    [slider setValue:lroundf(slider.value) animated:YES];
}

but the problem is, that the popUp label is not exactly following the slider when it "snaps" to an integer value. The other reason why I prefer to use my solution is that I am able to set the steps as float, so that I can also "snap" every 0.2 steps or so.

But I will be very glad when you implement something like:

- (NSString *)trackingSlider:(ASValueTrackingSlider *)slider stringForValue:(float)value;

That would be great!

The idea with "self.popUpLabels" array is exactly what would be useful in this case:

- (void)viewDidLoad
{ 
    self.popUpLabels = @[@"A", @"B", @"C", @"D", @"E"];
    self.slider.minimumValue = 0;
    self.slider.maximumValue = 4;
}

Thanks again,
Kenan.

@alskipp
Copy link
Owner

alskipp commented May 7, 2014

Hi Kenan,
To fix the popUpView not updating correctly when animating, replace - (void)setValue:(float)value animated:(BOOL)animated in ASValueTrackingSlider.m with the following:

- (void)setValue:(float)value animated:(BOOL)animated
{
    if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {
        [super setValue:value animated:animated];
        [self positionAndUpdatePopUpView];
    }
    else {
        [UIView animateWithDuration:0.25 animations:^{
            [super setValue:value animated:animated];
            [self positionAndUpdatePopUpView];
        }];
    }
}

The current implementation only updates the popUpView if self.popUpViewAlwaysOn == YES. I must change that in the next update!

@appicus
Copy link
Author

appicus commented May 7, 2014

What exactly my problem is I can't adjust the size of popUpView size for a String. You do it with NSNumberFormatter like this:

- (void)positionAndUpdatePopUpView
{
    [self adjustPopUpViewFrame];
    [self.popUpView setString:[_numberFormatter stringFromNumber:@(self.value)]];
    [self.popUpView setAnimationOffset:[self currentValueOffset]];

    [self autoColorTrack];
}

How can I modify this method to send a String instead of:

[_numberFormatter stringFromNumber:@(self.value)]];

EDIT:

- (void)positionAndUpdatePopUpView
{
    [self adjustPopUpViewFrame];
    //[self.popUpView setString:[_numberFormatter stringFromNumber:@(self.value)]];
    [self.popUpView setString:@"Lorem Ipsum"];
    [self.popUpView setAnimationOffset:[self currentValueOffset]];

    [self autoColorTrack];
}

I got this issue:

image

... just "Lore" instead of full string "Lorem Ipsum".

Thanks!

@alskipp
Copy link
Owner

alskipp commented May 7, 2014

I've just published another branch https://github.com/alskipp/ASValueTrackingSlider/tree/custom_string

It has a first draft implementation of:

@protocol ASValueTrackingSliderDataSource <NSObject>
- (NSString *)slider:(ASValueTrackingSlider *)slider stringForValue:(float)value;
@end

It was a very quick hack, so I can't guarantee it's perfect just yet! You just need to adopt the protocol ASValueTrackingSliderDataSource in your controller, set your controller as the dataSource for the slider self.slider.dataSource = self;, then implement:

- (NSString *)slider:(ASValueTrackingSlider *)slider stringForValue:(float)value;

Let me know if it works as I've barely tested it myself!

@appicus
Copy link
Author

appicus commented May 7, 2014

8mzp7

As you can see it works like a charm! THANKS a lot! Kenan

@alskipp
Copy link
Owner

alskipp commented May 7, 2014

Great stuff! I'm glad it's working. 👍 Good luck with your app.

@alskipp alskipp closed this as completed May 8, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants