Kodeco Forums

Custom Control for iOS Tutorial: A Reusable Knob

Elegant custom controls are the foundation of great iOS 7 apps. This custom UI tutorial shows you how to build a unique, reusable knob control.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/2566-custom-control-for-ios-tutorial-a-reusable-knob

Hi, I have everything in the tutorial working, but I am trying to modify the code so that the knob can be initialized in the middle, rather than starting off always pointing to the lowest value. I have set minimum and maximum to bipolar values -12.0 and 12.0 respectively.

When I add _knobControl.value = 0.0 to the viewController’s viewDidLoad() it still initializes it at the lowest point, but when I do _knobControl.value = 0.01 it succeeds in changing it. Tried the same thing calling the method [_knob setValue: 0.00 animated: YES]; with the same result. This is especially weird since I succeed in setting the value to zero later in my program through a textField object.

Any idea what might be causing this? I am using 0.01 right now, but its kind of a work around so I’d rather solve the issue. Please let me know.

Also, thanks for the great tutorial, I found it very informative on the general nature of iOS programming while also providing the framework for creating something really useful and reusable. Perfect thing for someone who is just starting out.

1 Like

I can’t remember the code, but it sounds to me like the control is only updating its appearance if the value is changed. You might be able to fix this by removing that check, if it exists.

This kind of problem is indicative of an ordering issue in the code: the layout is happening early, and then doesn’t update when you set the value to 0 because it doesn’t think it needs to perform a new layout pass because the value hasn’t changed. Check that you’re adding your range customisations before the control performs its initial layout pass.

Hope that helps

sam

That makes sense. When I set the value to 1 then back to 0 it starts at 0. Again a workaround, but I’m not to worried about it at this point. Thanks for your help.

Actually I started for creating frameworks from there I came here to practise this tutorial.
I am going through your tutorial from the beginning and I encountered an error while doing “RWKnobRender.h”

I am using Xcode 7.3.1. What might be the the reason?Thanks in advance.

Hi @kanna18

The problem is that you’re using types that aren’t declared in Foundation.h. You also need to import the CoreGraphics and CoreAnimation modules:

@import CoreGraphics
@import CoreAnimation

Hope that helps

sam

1 Like

Thanks Sam that Worked it also needs @import UIKit.

1 Like

@samdavies Hi, Thanks for the great tutorial. I wanted to customize the UI of this control and i already did it.

I Customize the control as below :

  1. Instead of line pointer i used circle(arc).
  2. Added another arc for progress(to show progress color).

Problem :

  1. I want to change the value of control only if user drag from the pointer.
  2. When i added control to UITableViewCell it’s hard to scroll the tableview.

Hi @mdhapa

  1. You can do that by checking where the first touch appears in the custom gesture recogniser subclass. Only recognise the gesture if the first touch is within a reasonable vicinity of the pointer.
  2. If you place something like this in a table view, then it’ll absorb the touches, and not pass them onto the tableview. That is what makes the tableview difficult to scroll. You can investigate touch handling and multiple gesture recognisers to see what you might do here, but you’re always likely to have an issue with nested touch responsive elements.

sam

@samdavies thank you so much for your help. Yesterday i work around and find the solution for both problems.

I added following solution to custom gesture recogniser subclass and solved my both problems.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    self.touchLocation = [[touches anyObject] locationInView:self.view];

    // Check if touch location is inside the pointer
    if (![self.knobControl isValidTouch:self.touchLocation]) {
        return;
    }

    [super touchesBegan:touches withEvent:event];
    [self updateTouchAngleWithTouches:touches];
}

if anybody wish to see full changes please write to me.

Regards,
Mahesh.

1 Like

hi, Sam,

Great tutorial, thanks. I wonder if there a way to not let the knob control jump from max to min or min to max across the gap directly when you drag your finger far enough? I have been trying to solve this issue for several days, but am unable to solve it. Do you have any suggestions regarding this issue? Thanks in advance.

@brina

In order to do something like that I think you need to track the current value or angle of the pointer, and then prevent it from making that jump.

A potential quick and dirty solution might be to set a limit on size of the allowed value change when interacting via the gesture recogniser: if the jump is too large, then prevent that change. That way you would expect people to actually rotate the pointer.

I suspect that there will be subtle issues with this approach, but it might offer a reasonable starting point.

sam

This tutorial is more than six months old so questions are no longer supported at the moment for it. We will update it as soon as possible. Thank you! :]