Keep subviews as original dimensions in UIStackView - ios

Currently I'm trying to make 3 buttons in a horizontal group of 3 that have equal spacing
UIStackView * menuButtons = [[UIStackView alloc] initWithFrame:CGRectMake(0, 0, 60, 16)];
menuButtons.axis = UILayoutConstraintAxisHorizontal;
menuButtons.alignment = UIStackViewAlignmentBottom;
menuButtons.spacing = 6;
menuButtons.distribution = UIStackViewDistributionEqualSpacing;
UIButton* btnOne = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 16, 16)];
UIButton* btnTwo = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 16, 16)];
UIButton* btnThree = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 16, 16)];
[menuButtons addArrangedSubview:btnOne];
[menuButtons addArrangedSubview:btnTwo];
[menuButtons addArrangedSubview:btnThree];
ive noticed when I inspect the frame of the button views after adding them to my stackview programatically, they all show different sizes than originally set, when I expect them all to still be 16
ie: btnOne CGSize(17, 16), btnTwo CGSize(23.5, 23,5), btnThree CGSize(21.3, 21.3)
I don't understand why this happens, and I've tried all the distributions but I can't figure this out when I'm not setting the frames on these views anywhere else

Here is an example - based on your code - using auto-layout constraints.
Note that you do NOT need to specify width and height constraints for your UIStackView, as it will expand as needed to fit the arranged subviews.
If you do set a width constraint, you'll end up with (likely) unexpected results, because you've also specified fixed-width spacing of 6.
So, you would want either:
width constraint + UIStackViewDistributionEqualSpacing, or
no width constraint + default distribution + .spacing = 6
Hope this helps...
//
// StackTestViewController.m
//
// Created by Don Mag on 6/24/17.
//
#import "StackTestViewController.h"
#interface StackTestViewController ()
#end
#implementation StackTestViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupMenuButtons];
}
- (void)setupMenuButtons {
// instantiate a UIStackView
UIStackView *menuButtons = [[UIStackView alloc] init];
// horizontal
menuButtons.axis = UILayoutConstraintAxisHorizontal;
// spacing between arranged views
menuButtons.spacing = 6;
// instantiate 3 buttons
UIButton* btnOne = [UIButton new];
UIButton* btnTwo = [UIButton new];
UIButton* btnThree = [UIButton new];
// give 'em background colors so we can see them
btnOne.backgroundColor = [UIColor redColor];
btnTwo.backgroundColor = [UIColor greenColor];
btnThree.backgroundColor = [UIColor blueColor];
// for each button,
// tell it not to use Autoresizing Mask
// set width and height constraints each to 16
for (UIButton *b in #[btnOne, btnTwo, btnThree]) {
[b setTranslatesAutoresizingMaskIntoConstraints:NO];
[b.widthAnchor constraintEqualToConstant:16.0].active = YES;
[b.heightAnchor constraintEqualToConstant:16.0].active = YES;
}
// add them to the Stack View
[menuButtons addArrangedSubview:btnOne];
[menuButtons addArrangedSubview:btnTwo];
[menuButtons addArrangedSubview:btnThree];
// add the Stack View to self view
[self.view addSubview:menuButtons];
// tell Stack View not to use Autoresizing Mask
[menuButtons setTranslatesAutoresizingMaskIntoConstraints:NO];
// set X and Y position for the Stack View (just using 80,80 for this example)
[menuButtons.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:80.0].active = YES;
[menuButtons.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:80.0].active = YES;
}
#end

Related

iOS - Resize UISwitch in UINavigationBar

I am trying to use a UISwitch in my UINavigationBar. I want a smaller switch than the default, so I am scaling the size down with anonymousSwitch.transform = CGAffineTransformMakeScale(0.55, 0.55); When I do this, the switch shrinks, but I cannot figure out how to align it vertically with the other elements in my UINavigationBar.
Here is what it looks like currently:
Ideally, the UISwitch would be spaced away from the 175 UILabel as much as the X UIButton is spaced from the 175 UILabel, and the UISwitch would be in a straight line with the rest of the elements in the UINavigationBar. I tried doing switch.center = CGPointMake(switch.center.x, shareButton.center.y), but this did not affect the placement of the UISwitch at all.
Is there any way for me to position the switch like I want?
I had the same problem.
I tried to solve it and came up with this solution.
I don't think it's a perfect solution and might not work on every iOS-Version.
First you need to subclass UISwitch like this:
#interface UICustomSwitch : UISwitch
#property (assign, nonatomic) CGFloat scale;
#end
#implementation UICustomSwitch
- (void)setFrame:(CGRect)frame {
CGFloat superview_height = self.superview.frame.size.height;
frame.origin.y = (superview_height - frame.size.height * _scale) / 2;
[super setFrame:frame];
}
#end
The second thing to do is to create and setup your UICustomSwitch like that:
UICustomSwitch* switch = [UICustomSwitch new];
switch.transform = CGAffineTransformMakeScale(0.75, 0.75);
switch.scale = 0.75;
UIBarButtonItem* button = [[UIBarButtonItem alloc] initWithCustomView:switch];
To create a bigger space between the 175 and the switch you could just add another UIBarButtonItem between the 175 and the switch. E.g. a fixed spacer with a specific width.
Like i said, i don't think it's a flawless solution.
In my tests it worked.
Another solution by 0yeoj (but a little bit adjusted -> always centered for every navigationBar height, for toolbars it's the same, just use self.navigationController.toolbar.frame.size.height ):
UIView* switch_container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 44, self.navigationController.navigationBar.frame.size.height)];
UISwitch* switch = [[UISwitch alloc] initWithFrame:switch_container.bounds];
switch.transform = CGAffineTransformMakeScale(0.75, 0.75);
switch.center = CGPointMake(switch_container.bounds.size.width/2, switch_container.bounds.size.height/2);
[switch addTarget:self action:#selector(action:) forControlEvents:UIControlEventValueChanged];
[switch_container addSubview:switch];
UIBarButtonItem* button = [[UIBarButtonItem alloc] initWithCustomView:switch_container];
self.navigationItem.rightBarButtonItem = button;
Have you tried moving switch with another transform method like,
CGAffineTransformMakeTranslation(xValue, yValue);
also you can merge two transform together and give that transform to switch like,
CGAffineTransform scale= CGAffineTransformMakeScale(0.55, 0.55);
CGAffineTransform translate = CGAffineTransformMakeTranslation(0, 10);
anonymousSwitch.transform = CGAffineTransformConcat(scale, translate);
This is the code i tested..
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIButton *xbutton = [UIButton buttonWithType:UIButtonTypeCustom];
xbutton.frame = CGRectMake(0, 6, 35, 35);
xbutton.backgroundColor = [UIColor redColor];
UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
UISwitch *switchButton = [[UISwitch alloc] init];
switchButton.frame = CGRectMake(0, 0, 35, 35);
switchButton.transform = CGAffineTransformMakeScale(0.55, 0.55);
switchButton.center = CGPointMake(containerView.frame.size.width/2, containerView.frame.size.height/2);
[containerView addSubview:switchButton];
UIBarButtonItem *additionalButton = [[UIBarButtonItem alloc] initWithCustomView:containerView];
UIBarButtonItem *xBarButton = [[UIBarButtonItem alloc] initWithCustomView:xbutton];
//rearrange it if necessary
NSArray *arrayButton = [NSArray arrayWithObjects: xBarButton, additionalButton, nil];
self.navigationItem.leftBarButtonItems = arrayButton;
}.
hmm... i haven't DOWNGRADED yet to yosemite so i dont have ios8.3 here this code works perfectly for me though..

iOS Calc X position to place elements on a View

I want to add a Label and an Image in titleView of my NavigationItem. I am adding UILabel and UIImageView to a UIView and setting it as titleView of the navigation Item. Things are being added, but I am not able to calculate the length of label and place image next to it.
My code is :-
// Title Name + Image
UIView *titView = [[UIView alloc] initWithFrame:self.navigationItem.titleView.bounds];
self.navigationItem.titleView = titView;
UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(-10, -20, 150, 30)];
title.text = #"Bunny ";
[title setTextColor:[UIColor orangeColor]];
[titView addSubview:title];
float x2 = 30; //+ title.bounds.size.width;
UIImageView *img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"return" ]];
img.frame = CGRectMake(x2, -20, img.bounds.size.width, 30);
[titView addSubview:img];
I am looking for some way to calc the width text and set accordingly the width of the label. Right now I have set the width of the label as 150. And secondly, calc the x position to place the image just next to the label.
Tried many ways, but nothing works as expected. How can I achieve this ? Can you he give some guidelines such that regardless of length of text of label, things works as expected and UIView gets placed in the center of navigation item.
Any help is highly appreciated. Thanks.
You can call
[title sizeToFit];
after setting its properties and it will size itself to match the contained string.
Set the imageViews x origin to
CGRectGetMaxX(title.frame) + desiredSpacing;
And it could help to subclass UIView to achieve the final results by overwriting layoutSubviews and placing your views there, since the titleView's frame can be adjusted by the navigationBar...basically like this:
#implementation TitleView{
UILabel *_titleLabel;
UIImageView *_img;
}
- (id)initWithTitle:(NSString *)title andImage:(UIImage *)image
{
self = [super init];
if (self) {
_titleLabel = [[UILabel alloc] init];
_titleLabel.text = title;
[_titleLabel setTextColor:[UIColor orangeColor]];
[_titleLabel sizeToFit];
[self addSubview:_titleLabel];
_img = [[UIImageView alloc] initWithImage:image];
[self addSubview:_img];
}
return self;
}
- (void)layoutSubviews{
CGFloat spacingBetweenTextAndImage = 0;
CGFloat width = CGRectGetWidth(_titleLabel.frame)+CGRectGetWidth(_img.frame)+spacingBetweenTextAndImage;
CGFloat x = (CGRectGetWidth(self.bounds)-width)/2;
_titleLabel.frame = CGRectMake(x, (CGRectGetHeight(self.bounds)-CGRectGetHeight(_titleLabel.bounds))/2, CGRectGetWidth(_titleLabel.bounds), CGRectGetHeight(_titleLabel.bounds));
x+=CGRectGetWidth(_titleLabel.bounds)+spacingBetweenTextAndImage;
_img.frame = CGRectMake(x, (CGRectGetHeight(self.bounds)-CGRectGetHeight(_img.bounds))/2, CGRectGetWidth(_img.bounds), CGRectGetHeight(_img.bounds));
}
#end
use in your viewController:
UIView *titleView = [[TitleView alloc] initWithTitle:#"Bunny" andImage:[UIImage imageNamed:#"return" ]];
self.navigationItem.titleView = titleView;

UIScrollView setContentOffset will add a subview to the scrollview?

I happened to find that setContentOffset to a UIScrollView will cause the scrollView append a new view to its subviews. here is the code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake((320 - 261) / 2, 50, 261, 67)];
scrollView.pagingEnabled = YES;
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.bounces = NO;
scrollView.backgroundColor = [UIColor darkGrayColor];
for (int i = 0; i < 5; i ++) {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(i * 87, 1, 87, 65)];
view.tag = i;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 50, 30)];
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor whiteColor];
label.text = [NSString stringWithFormat:#"%d", i];
[view addSubview:label];
view.backgroundColor = [UIColor greenColor];
[scrollView addSubview:view];
}
scrollView.contentSize = CGSizeMake(87 * 5, 67);
NSLog(#"before scroll: count of subview is %d", scrollView.subviews.count);
CGPoint offset = CGPointMake(87, 0);
[scrollView setContentOffset:offset animated:YES];
NSLog(#"after scroll: count of subview is %d", scrollView.subviews.count);
[self.view addSubview:scrollView];
}
Before calling setContentOffset:offset, the number of subviews of the scrollView is 5. This is what I expect. After that, the number turns to be 6.
Is it working as designed? How to avoid the new subview appended?
The extra subview is the scroll indicator. If you check again in a later method, it will have gone away. Don't worry.
You can confirm this by hiding the scroll indicators (showsVerticalScrollIndicator and showsHorizontalScrollIndicator properties).
Don't try to assume things about the view hierarchy of UIKit classes. UIKit can, and does, add its own views to several things - see tableviews and their cells, a navigation controller's view and so on.

How to add vertical space between UINavigationBar and UISegmentedControl?

I'm working with my UI completely programmatically here. When I add a UISegmentedControl to my UITableViewController's header view, it just fixes itself up there with no vertical space between the UINavigationBar. How can I add some padding between the UISegmentedControl and the UINavigationBar ?
Instantiate a UIView object and add your UISegmentedControl as a subview. Then set the UIView as your table's headerView. You'll be able to add padding by adjusting the frame of the UIView you created.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 150 /* <-- adjust this value for more or less padding */)];
UISegmentedControl *segControl = [[UISegmentedControl alloc] initWithItems:#[#"One", #"Two", #"Three"]];
segControl.frame = CGRectMake(0, 90, 200, 29);
//calculate the middle of the header view
CGFloat middleOfView = headerView.bounds.size.width / 2;
CGFloat middleOfSegControl = segControl.bounds.size.width / 2;
CGFloat middle = middleOfView - middleOfSegControl;
//position the seg control in the middle
CGRect frame = segControl.frame;
frame.origin.x = middle;
segControl.frame = frame;
[headerView addSubview:segControl];
self.theTableView.tableHeaderView = headerView;
}
Of course you can mess with the frames some more to get things positioned like you want them.

how can i put the ScrollView on ViewController

I am trying to put the Scrollview on the viewcontroller? is it possible? and i also want to put the UIView on the ScrollView.
UIScrollView *scrollView =[[UIScrollView alloc]initWithFrame:CGRectMake(20, 60, 280, 200)];
scrollView.contentSize = CGSizeMake(280, 200);
scrollView.backgroundColor=[UIColor orangeColor];
scrollView.delegate = self;
[self.view addSubview:scrollView];
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(20, 60, 280, 200)];
container.backgroundColor = [UIColor whiteColor];
[scrollView addSubview:container];
In this code i tried to put the scrollview on the VC and also i tried to put View on the ScrollView.
rb1 = [[RadioButton alloc] initWithGroupId:#"first group" index:j];
rb1.frame = CGRectMake(20,dy,22,22);
[container addSubview:rb1];
[rb1 release];
label1 =[[UILabel alloc] initWithFrame:CGRectMake(50, dy, 60, 20)];
label1.backgroundColor = [UIColor clearColor];
label1.text = [answers objectAtIndex:j];
[container addSubview:label1];
and here i tried to put the a radio button on View.
I hope it is clear:) Sorry my bad english.Thanks.
Scroll occurs when the frame of a scroll view is less than your content size.
Your frame is having size (280,200) and you have provided same size to contentSize.
To make the scroll possible replace below line into your code.
scrollView.contentSize = CGSizeMake(300, 260);
Here you put the same content size as scroll size:
scrollView.contentSize = CGSizeMake(280, 200);
In content size you should enter the size of area you want to scroll. In your case scroll does not need to scroll because scrollable area is same as scrollView size.
try this to put the scrollview on the controller
#import <UIKit/UIKit.h>
#interface YourClass : UIViewController {
IBOutlet UIScrollView *scrollView;
}
#property (nonatomic, retain) UIScrollView *scrollView;
#end
to put v/v try this
NSUInteger scrollContentCount = 0;
for (NSUInteger arrayIndex = 0;
arrayIndex < [contents count];
arrayIndex++) {
// set scorllview properties
CGRect frame;
frame.origin.x = self.mScrollView.frame.size.width * arrayIndex;
frame.origin.y = 0;
frame.size = self.mScrollView.frame.size;
myScrollView.autoresizingMask = YES;
// alloc - init PODetailsView Controller
myController = [[MyController alloc] initWithNibName:#"MyController" bundle:[NSBundle mainBundle]];
[myController.view setFrame:frame];
// add view in scroll view
[self.myScrollView addSubview:myController.view];
scrollContentCount = scrollContentCount + 1;
}
// set scroll content size
self.myScrollView.contentSize =
CGSizeMake(self.myScrollView.frame.size.width * scrollContentCount,
self.myScrollView.frame.size.height);
}

Resources