Code Monkey home page Code Monkey logo

svsegmentedcontrol's Introduction

SVSegmentedControl

SVSegmentedControl is a customizable UIControl class that mimics UISegmentedControl but that looks like an UISwitch.

SVSegmentedControl

Installation

From CocoaPods

Add pod 'SVSegmentedControl' to your Podfile or pod 'SVSegmentedControl', :head if you're feeling adventurous.

Manually

Important note if your project doesn't use ARC: you must add the -fobjc-arc compiler flag to SVSegmentedControl.m and SVSegmentedThumb.m in Target Settings > Build Phases > Compile Sources.

  • Drag the SVSegmentedControl/SVSegmentedControl folder into your project.
  • Add the QuartzCore framework to your project.

Usage

(see sample Xcode project in /Demo)

In its simplest form, this is how you create an SVSegmentedControl instance:

segmentedControl = [[SVSegmentedControl alloc] initWithSectionTitles:[NSArray arrayWithObjects:@"Section 1", @"Section 2", nil]];
segmentedControl.changeHandler = ^(NSUInteger newIndex) {
    // respond to index change
};

[self.view addSubview:segmentedControl];

You can position it using either its frame or center property:

Customization

SVSegmentedControl can be customized with the following properties:

@property (nonatomic, strong) NSArray *sectionTitles;
@property (nonatomic, strong) NSArray *sectionImages;

@property (nonatomic, readwrite) BOOL animateToInitialSelection; // default is NO
@property (nonatomic, readwrite) BOOL crossFadeLabelsOnDrag; // default is NO

@property (nonatomic, readwrite) BOOL mustSlideToChange; // default is NO - To make the control difficult to accidentally change, force the user to slide it
@property (nonatomic, readwrite) CGFloat minimumOverlapToChange; // default is 0.66 - Only snap to a new segment if the thumb overlaps it by this fraction
@property (nonatomic, readwrite) UIEdgeInsets touchTargetMargins; // default is UIEdgeInsetsMake(0, 0, 0, 0) - Enlarge touch target of control

@property (nonatomic, strong) UIColor *backgroundTintColor; // default is [UIColor colorWithWhite:0.1 alpha:1]
@property (nonatomic, retain) UIImage *backgroundImage; // default is nil

@property (nonatomic, readwrite) CGFloat height; // default is 32.0
@property (nonatomic, readwrite) UIEdgeInsets thumbEdgeInset; // default is UIEdgeInsetsMake(2, 2, 3, 2)
@property (nonatomic, readwrite) UIEdgeInsets titleEdgeInsets; // default is UIEdgeInsetsMake(0, 10, 0, 10)
@property (nonatomic, readwrite) CGFloat cornerRadius; // default is 4.0

@property (nonatomic, retain) UIFont *font; // default is [UIFont boldSystemFontOfSize:15]
@property (nonatomic, retain) UIColor *textColor; // default is [UIColor grayColor];
@property (nonatomic, strong) UIColor *innerShadowColor; // default is [UIColor colorWithWhite:0 alpha:0.8]
@property (nonatomic, retain) UIColor *textShadowColor;  // default is [UIColor blackColor]
@property (nonatomic, readwrite) CGSize textShadowOffset;  // default is CGSizeMake(0, -1)

Its thumb (SVSegmentedThumb) can be customized as well:

@property (nonatomic, retain) UIImage *backgroundImage; // default is nil;
@property (nonatomic, retain) UIImage *highlightedBackgroundImage; // default is nil;

@property (nonatomic, retain) UIColor *tintColor; // default is [UIColor grayColor]
@property (nonatomic, assign) UIColor *textColor; // default is [UIColor whiteColor]
@property (nonatomic, assign) UIColor *textShadowColor; // default is [UIColor blackColor]
@property (nonatomic, readwrite) CGSize textShadowOffset; // default is CGSizeMake(0, -1)
@property (nonatomic, readwrite) BOOL shouldCastShadow; // default is YES (NO when backgroundImage is set)
@property (nonatomic, assign) CGFloat gradientIntensity; // default is 0.15

To customize the thumb's appearance, you'll have to set the properties through SVSegmentedControl's thumb property. For instance, setting the thumb's tintColor is done with:

segmentedControl.thumb.tintColor = someColor;

Responding to value changes

You can respond to value changes using a block handler:

segmentedControl.changeHandler = ^(NSUInteger newIndex) {
    // respond to index change
};

If you haven't fallen in love with blocks yet, you can still use the classic UIControl method:

[mySegmentedControl addTarget:self action:@selector(segmentedControlChangedValue:) forControlEvents:UIControlEventValueChanged];

Providing an action method ending with a semicolon, the sender object is therefore made accessible:

- (void)segmentedControlChangedValue:(SVSegmentedControl*)segmentedControl {
	NSLog(@"segmentedControl did select index %i", segmentedControl.selectedIndex);
}

Credits

SVSegmentedControl is brought to you by Sam Vermette and contributors to the project. If you have feature suggestions or bug reports, feel free to help out by sending pull requests or by creating new issues. If you're using SVSegmentedControl in your project, attribution would be nice.

svsegmentedcontrol's People

Contributors

capnslipp avatar danielctull avatar domesticcatsoftware avatar fabienditore avatar gcamp avatar grantjk avatar jeksys avatar jhersh avatar jinthagerman avatar oliverletterer avatar rhubarb avatar samvermette avatar thantthet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

svsegmentedcontrol's Issues

Change handler block can cause a retain cycle.

I'm getting the following warning in XCode 4.5 when I use some code like this. I have the segmented control as a private ivar in the view controller.

warning

[__segmentedControl setChangeHandler:^(NSUInteger index) {
    [self fooBar:index + 1];
}];

This is due to the fact the segmented control class retains the block (therefore causing a retain cycle). Could you suggest anything?

Thanks! Awesome work!

There is a way to add it on a UITableViewCell?

Hello, i have a uitableview, with different type of cell, that display different value, and i want insert the SVSegmentedControl, only on one specific UITableViewCell, i have tried using cell.contentView addsubivew on that specfic cell, but if i scroll the uitableview fast i see the SVSegmentedControl also on other cell, so my question is there is a way to insert the UITableViewCell only on a specific cell?

Wrong callback using "changeHandler" block

This problem doesn't occur using the target-action method
On the first example, changeHandler is triggered when the thumb hits the right side of the segment, not on "mouse up"
so for example you could keep sliding the thumb back to position 0 and it would still think it is at index 1...

Drag problem in Facebook layout type.

Hi, first of all, congratulations for the wonderful uicontrol.
I've used several times your switch, no problem. But now I have implemented it in a Facebook layout type, a draggable view. When move the thumb, arrives in the middle and come back. With a single touch does work.

You know how to solve this problem?

Thanks man

Changing Properties after Initialization

I have having some problems when changing the height and segmentPadding after the view has been placed. I have to resize a bit in landscape, but the view is not changing at all. I even tried calling setNeedsDisplay: on it.

Other than that, it is working great. Keep up the good work.

Value is not updated when change handler is called

I'm calling a method that updates the UI depending on the current selected segment index. But the code doesn't work because the selectedSegmentIndex has not yet been updated when the handler is called.

You can see in the log from this statement that they are not in sync, selectedSegmentIndex is always one step behind:

self.segmentedControl.changeHandler = ^(NSUInteger newIndex) {
    NSLog(@"New index: %d, Current index: %d", newIndex, self.segmentedControl.selectedSegmentIndex);
    [self updateUI];
};

The regular event works fine and selectedSegmentIndex is updated when the below method is called. But I like blocks much better, too bad it doesn't work as good.

[self.segmentedControl addTarget:self action:@selector(segmentedControlChangedValue) forControlEvents:UIControlEventValueChanged];

SVSegmentedControl set selected index to none

Dear Sir,

I am considering using your (excellent) SVSegmentedControl in one of my iPhone apps, along with the appropriate attribution (of course). I am having difficulty, however, setting all segments to the OFF state, something like this:

[mySVSegmentedControl setSelectedSegmentIndex: UISegmentedControlNoSegment]

or even:

[mySVSegmentedControl setSelectedSegmentIndex: -1]

Your code does not seem to allow this (exception error, plus segment index is NSUInteger (unsigned integer)). Is it possible to get around this?

Please advise.

Best regards,
R. Preston

Delegate methods called on willMoveToSuperview:

Not sure if this is intentional, but when adding the control to a view it calls the delegate method straight away (with the selected segment being 0). This is because of the call to [self moveThumbToIndex:0 animate:NO]; inside willMoveToSuperview:. Removing that call fixes the problem but I'm not sure what else this might effect.

Image-only segments have the image offset to the left

This is true whenever you have only images (and I've not tested for images + text) but you notice it especially if you have a single-segment (that's right, single - your control is very nice for use as a button in a UIBarButtonItem) and especially if the image is symmetric. See here
http://d.pr/i/x0ST
(cool service this Droplr, thanks again for the tip)

Note that the center of the Plus is left-of-center by 2 pixels.
It turns out that this is because of the 5 pixel "fudge factor" you add every time you use the image.width.
Now, I haven't attached a patch because I'm not sure of what the correct fix is, but for me simply commenting out the +5 in this line in drawRect in SVSegmentedThumb.m does the trick:

imageWidth = image.size.width; //+5;

I'm not sure about the other cases though. I was frustrated for a while trying to debug this because I though this image was being painted in drawREct in SVSegmented_Control_.m instead of the Thumb, and commenting out the 2 +5's in that class had no effect. In any case, this single commenting-out fixes it for me, but I assume I'm breaking some other use case.
What was the fudge factor for?

If it is indeed necessary - the correct fix might be to simply account for it when calculating the drawing position (ie subtract it from the width again)

Would anyone be willing to provide some guidance on a customization?

I’m using SVSegmentedControl in our app and we’d like to have the text for the non-selected or non-active position be semi-opaque. I’ve really tried for a long time to figure this out without success. Would you be willing to provide any direction on setting the opacity on the non-active label?

SVSegmentedControl.m

  • (void)willMoveToSuperview:(UIView *)newSuperview {

    if(newSuperview == nil)
    return;

    int c = [self.titlesArray count];
    int i = 0;

// self.segmentWidth = 0;

self.segmentWidth = (([UIScreen mainScreen].bounds.size.width) / (([self.titlesArray count] == 0)?1:[self.titlesArray count]));

problem when setting selectedIndex (edit: solved)

I use 6 segmentedControls. Whenever I try to set them using the value I get saved in userDefaults the app crashes. Is there something special about how to set the selectedIndex value?
Code sample below.

    _sectionsControl = [[SVSegmentedControl alloc] initWithSectionTitles:[NSMutableArray arrayWithObjects:@"On", @"Off", nil]];
    self.sectionsControl.delegate = self;
    self.sectionsControl.center = CGPointMake(240, 22);
    self.sectionsControl.selectedIndex = [self.standardDefaults valueForKey:kIKSectionscontrol];
    self.sectionsControl.selectedSegmentChangedHandler = ^(id sender) {
            SVSegmentedControl *sc = (SVSegmentedControl *)sender;
            switch (sc.selectedIndex) {
            case 0:
                        [self.standardDefaults setValue:[NSNumber numberWithUnsignedInteger:0] forKey:kIKSectionscontrol];
                        break;
            case 1:
                        [self.standardDefaults setValue:[NSNumber numberWithUnsignedInteger:1] forKey:kIKSectionscontrol];
                        break;
            default:
                        break;
            }
    };
    [cell.contentView addSubview:self.sectionsControl];

EDIT: I found my mistake. I should use
self.sectionsControl.selectedIndex = [[self.standardDefaults valueForKey:kIKSectionscontrol] integerValue];
otherwise this won't work. I won't delete this, perhaps somebody else has the same question.

How Can I increase title's numberOfLines

I want to increase the numberOfLines for the title. If the segmented control height is 48 & restricted width , then how can I make the title to spread over two lines.
Please help.

Cancel index changes for every tap

Hey thanks for sharing,

I see that with a two section segmented control the selected index changes for every tap, even if same section was tapped.
For example if now the selected index is 1, and I tap on section 1 the index will now change to 2, although i didn't tap on 2 I re-tap on 1..
Is there a way to cancel this behavior?

UIControlEventValueChanged Firing on Creation

Hi there,
Your control is awesome and thanks for all the hard work.

I am having a minor issue with the event UIControlEventValueChanged - i have a selector for the event, but i do not want the selector to fire when the control is created. In this case, the event is fired in the start when the control is created.

How can i avoid it? Ofcourse without having to manually creating a flag variable.

Regards

issue When i added the -fobjc-arc

HI

Nice work by you,Currently when i tried using your code im facing issues.
mine is NON - ARC.i have even followed your instructions as follows
Important note if your project doesn’t use ARC: you must add the -fobjc-arc compiler flag to SVSegmentedControl.m in Target Settings > Build Phases > Compile Sources.

but still im facing the problem.mine is Xcode4.2

Thanks
Siva

Changing 'selectedIndex' property after adding instance to view has no effect. (solution: use moveThumbToIndex:animate: instead)

Hi all.
I was implementing the "set defaults" routine for some instances of SVSegmentedControl, but I have trouble with setting selectedIndex' property.

The code below will be enough to perform this situation :

SVSC = [[SVSegmentedControl alloc] initWithSectionTitles:[NSArray arrayWithObjects:@"zero", @"one", nil]];

// some customization ...

SVSC.selectedIndex = 1;

[self.workArea addSubview:SVSC ];

SVSC.selectedIndex = 0;

In result I have selected the item "one", not "zero".

Is there any suggestion how to this manipulation take effect?
Or maybe i'm do something wrong?

Crash with more than 6 items in the Array

I have an array with more than 5 items and the demo app always crashes. If there is only 6 in the list, it is ok. When i add the 7th item, the application crashes with no crash log. The app simply quits.

Problem when use "changeHandler"

Hi, i find that when i user "changeHandler", my ViewController which add the SVSegmentedControl can not be dealloc.
However , it going right when i use the classic UIControl method. the ViewController can be dealloc.

Horizontal orientation issue

Nice code but there is a bug when orientation switched to landscape. The view is not updated along with its thumbs.

the SVSegmentedControl setFrame method should also call [self updateSectionRects] to update the section rects which works fine except that new correct thumbrects are added also but to an existing array so if have 6 thumbrects , 6 new correct thumbrects are at the end of the array. self.thumbrects should removeAllObjects before addObject loop...

When an app calls setFrame in a landscape or portrait change to adjust the SVSegmentedControl size the the section fixes one thing and updates the control but not the thumbs (self.thumbrects). The loop in updateSectionRects does an addObject to self.thumbrects to add the correct new thumb rects, however, if self.thumbrects already exists a [self thumbrects removeAllObjects] should be called first otherwise keep adding rects.

White tint color

Setting the tint color as white has practically no effect since the background of the segmented control will remain a dark gray gradient.

Hi

textShadowColor is not well, if have images

problem with setSelectedSegmentIndex:animated:

I'm using old way for tracking changes (addTarget:action:forControlEvents:)

- (void)setSelectedSegmentIndex:(NSUInteger)index animated:(BOOL)animated {
    _selectedSegmentIndex = index;

    if(self.superview) {
        [self sendActionsForControlEvents:UIControlEventValueChanged];

sendActionsForControlEvents called even if selected segment not changed

Background color change

I'm trying to change the background color of the segment itself NOT the slider to White.

I tried changing segment.backgroundColor and segment.tintcolor to White but it wouldn't change.

Please help

Issues with iOS 7 beta

These errors are thrown in the log on opening any view that contains an SVSegmentedControl.

Jun 16 15:52:22 jaydens-mac-pro Ambiance[2037] <Error>: CGContextScaleCTM: invalid context 0x0
Jun 16 15:52:22 jaydens-mac-pro Ambiance[2037] <Error>: CGContextTranslateCTM: invalid context 0x0
Jun 16 15:52:22 jaydens-mac-pro Ambiance[2037] <Error>: CGContextSetFillColorWithColor: invalid context 0x0
Jun 16 15:52:22 jaydens-mac-pro Ambiance[2037] <Error>: CGContextBeginPath: invalid context 0x0
Jun 16 15:52:22 jaydens-mac-pro Ambiance[2037] <Error>: CGContextAddPath: invalid context 0x0
Jun 16 15:52:22 jaydens-mac-pro Ambiance[2037] <Error>: CGContextDrawPath: invalid context 0x0
Jun 16 15:52:22 jaydens-mac-pro Ambiance[2037] <Error>: CGBitmapContextCreateImage: invalid context 0x0

Update Git tag

Hey @samvermette,

Wondering if you could add a new Git tag — that way the CocoaPods spec could be updated with the merged pull requests, etc.

Thanks!

iOS7 style segment control UI?

Is it possible to create exactly same (replicate) iOS7 styled UISegementControl with SVSegmentedControl?

  • I'll need to change background and text colors for selected and unselected state.
  • I'll need to set color for seperator.
  • I'll need to give rounded border for segement control.

Here's the sample segment like iOS7

screen shot 2013-12-11 at 11 31 27 am

Is it possible?

NOTE: I can get it default in iOS7 but I want the same look in iOS5 and iOS6 as well.

Crossfade with images leaves ghost of alternative image

I'm using an SVSegmentedControl with two icon images with transparency (from Glyphish.com) and with no text labels: image only. I have crossFadeLabelsOnDrag set to YES and the images crossfade just like the text would.
However, whenever I slide the thumb to the rightmost of the two segments, the image remains just slightly cross-faded so that you see a ghost of the leftmost image. It doesn't happen the other way, and it only happens if you actually do the sliding.

As a side note: the textColor and textShadowColor properties affect transparent sections of the image in this mode when there is no text - but I find that actually useful, not sure if its intentional

About support without ARC

I'm sorry, my app not use ARC, and I'm new to the iPhone develop.
Is there any good way to support this project without ARC.

How to use ChangeHandler when user doesn't make a change.

How do I use the
svSC.ChangeHandler =^{
}

if the user doesn't make a change. I have a situation that user can tap an item and a SVSegmentedControl Pops Up. Why can't the user tap currently selected Item and have changehandler fire anyway.

The issue is I want to use blocks not delegate/callback method.

Thanks for this super cool control Sam!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.