Archive for October, 2010

Subscribe

I was searching for a different way to enter numeric values fast and precise without typing them digit by digit. The UIPickerView can handle predefined values from text to numbers, but it is really a big component. Using one picker view means having no space for anything else 😉 As an alternative you could use a UISlider, but especially for a huge range of values it might be difficult to pick an exact value. So I took a UISegmentedControl and extended it to use the center segment as slider and the surrounding segments as plus/minus buttons for fine adjustment:

If you tap on the left or right side segment, the related value is increased or decreased by 1. If you tap and hold on the center segment you can drag to left and right and the related value gets changed by the dragged distance. Quite simple to use in my eyes 🙂

As this component does not display the related value directly I decided to provide a protocol for a delegate to inform about slides and value changes. Furthermore I had several situations I could use the slider control where the values get handled in different ways. So I decided not to create a component that handles a specific value and offers this value directly, but use the component as trigger for a delegate that reacts on the slide or the button taps.

My component’s interface looks like this:

As you can see the component is derived from UISegmentedControl such that all the methods of a segmented control can be used, even the different layout styles. You can define a slide threshold (3px by default) that specifies how many dragged pixels trigger one step up or down. Furthermore you can define by the slider segment index which segment is used for sliding. By default the center segment (or right to center for even segment amount) is used.

How to use the UISliderControl

Although you can use the Interface Builder and a segmented control to layout your gui as usual, there are some things to do if you want to use a segmented control as slider. Instead of using a UISegmentedControl in your view controller class you have to offer UISliderControl outlets and implement the SliderControlDelegate protocol:

This example already contains two slider controls and a label for each to display the current value. Furthermore an action is required for each slider. This methods get called when one of the slider’s buttons not used for sliding gets pressed.

The view controller’s implemantation has to set up the slider controls when the view did load:

The slider controls have to know their delegate to inform when the slider is used. Furthermore I suggest to initialize the related values and write the setter method by hand to validate the value and update the related label:

A simple implementation for the action method that handles +1/-1 steps could look like this:

The attached sample project shows a further implementation to handle bigger steps and setting the maximum or minimum value. Attend that the action method gets called for the not-sliding segments only! When the user taps on the slider-segment the following methods from the slider delegate protocol get called:

The steps value is always positive and depends on the dragged distance and the slide threshold. If you use more than one slider control in one view controller you can use the slider control attribute to check which one did call the delegate.

So far with the programatical part, back to the Interface Builder… As I said you can use a segmented control to layout the gui. Now that your view controller offers all required outlets and actions you have to set the class used for the segmented control to “UISliderControl”:

After changing the class you can connect the controls with your view controller and you are done:

You find the component and a simple example app with the complete source code of the shown examples in this xcode project: SliderControl Xcode Project

To use the slider control in your project just drag and drop the group “SliderControl Sources” into your source tree.

If you have questions or suggestions, problems or complaints – the comment area is yours 🙂

[UPDATE: There was an error in the xcode project such that the class-files did not get included in the zip-file. I replaced the project with a working one.]

After dealing with some problems to add a single button as titleview of a UINavigationbar I decided to provide a small component to handle this scenario. There are several examples available showing how to add a segmented control in the center of a navigation bar, but as a segmented control has to contain at least two segments a single button could not get covered with that approach.

One could think a UIBarButtonItem would be the right choice to add a single button to a navigation bar. Setting left or right navigation bar buttons works fine that way, but not with the title view. As UIBarButtonItem is not a subclass of UIView, you can’t set it as title view. Therefore I prepared a UIButton to look like a UIBarButtonItem such that you can use it in three different ways:

with an icon: The button displays an icon and fits to the icon’s size

with a title: The button displays a title and fits to the text’s size

with a fixed width: The button has a given width, but no initial content

The class UINavbarButton is a subclass of UIButton without any further methods but the constructors:

The button can be used like in the following example:

The button gets allocated and initialized with an image and a selector that is called when the button gets pressed. The style attribute defines if the button is black or gray. The value can be read from the related navigation bar. After that the button instance gets assigned as title view of the main view’s navigation item and gets released. To get the example working “UINavbarButton.h” got imported before.

You find the component and a simple example app that shows all three kinds of usage for black and default navigation bar style in this xcode project: NavbarButton Xcode Project

To use the button in your project just drag and drop the group “NavbarButton Sources” in your source tree.