Rotate BarButtonItem by 45 degrees (animated) - ios

looks like animations are not my speciality :/
In my navigation bar I have a custom BarButtonItem, a plus, to add stuff to the list. I wanted to rotate the plus by 45 degrees so it becomes a X when it was pressed and works as a cancel button then.
I added a button as custom view to the BarButtonItem by doing this:
#IBOutlet weak var addQuestionaryButton: UIBarButtonItem!
{
didSet {
let icon = UIImage(named: "add")
let iconSize = CGRect(origin: CGPoint.zero, size: icon!.size)
let iconButton = UIButton(frame: iconSize)
iconButton.setBackgroundImage(icon, for: .normal)
addQuestionaryButton.customView = iconButton
iconButton.addTarget(self, action: #selector(QuestionaryListViewController.addClicked(_:)), for: .touchUpInside)
}
}
This seems to work fine.
Now if the button is pressed I do the following:
UIView.animate(withDuration: 0.5, animations:{
self.addQuestionaryButton.customView!.transform = CGAffineTransform(rotationAngle: CGFloat(M_PI_4))
})
I can see the button starting to rotate but somehow it gets totally deformed. See the pictures for that:
Before:
After:
I don't understand why this happens.
How do I correctly animate the BarButtonItem?
Thanks in advance.
Greetings

Don't know why this is happening(my guess is when doing the transform, the frame of the customView will be messed up) but found a solution.
Just put the button into another UIView and then set this UIView as the customView of the UIBarButtonItem.
When doing the animation, don't rotate the UIView, rotate the button.
Reminder: Don't forget to set the frame of this UIView.
Sample code in Objective C:
Init:
#interface ViewController ()
#property (nonatomic, strong) UIButton* itemButton;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//button init
self.itemButton = [[UIButton alloc] init];
[self.itemButton setBackgroundImage:[UIImage imageNamed:#"imgName"] forState:UIControlStateNormal];
self.itemButton.frame = CGRectMake(0, 0, 30, 30);
//container for the button
UIView* btnContainer = [[UIView alloc] init];
btnContainer.frame = CGRectMake(0, 0, 30, 30);
[btnContainer addSubview:self.itemButton];
//set the container as customView of the UIBarButtonItem
UIBarButtonItem* applyButton = [[UIBarButtonItem alloc] initWithCustomView:btnContainer];
self.navigationItem.rightBarButtonItem = applyButton;
}
Code to trigger the rotation:
[UIView animateWithDuration:0.5 animations:^{
self.itemButton.transform = CGAffineTransformRotate(self.itemButton.transform, M_PI_4);
}];

Related

iOS Navigation Item issues of extra padding top on landscape mode

There is extra padding top when my app in landscape.
Here is my code when create navigation bar programmatically.
Any advice to remove the padding top when in landscape mode?
let navigationBar = UINavigationBar(frame: CGRectMake(0, 0, self.view.frame.size.width, 44)
navigationBar.backgroundColor = UIColor.redColor()
navigationBar.delegate = self;
let navigationItem = UINavigationItem()
navigationItem.title = "Title"
let btnLeft = UIButton(frame: CGRectMake(0, 0, 44, 44))
btnLeft.setImage(UIImage(named: “myImage.png"), forState: .Normal)
let leftButton = UIBarButtonItem()
leftButton.customView = btnLeft
navigationItem.leftBarButtonItem = leftButton
navigationBar.items = [navigationItem]
self.view.addSubview(navigationBar)
Snapshot from simulator (Landscape)
Snapshot from simulator (Portrait)
You should easily solve with this setting (in your viewDidLoad for example):
self.edgesForExtendedLayout = UIRectEdge.None
Alternative: You can put it also in your UINavigationController delegate method (if you have setted in your class your navigation delegate UINavigationControllerDelegate ) called willShowViewController:
func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
viewController.edgesForExtendedLayout = UIRectEdge.None
}
If you work with UITableView you may also to do:
self.automaticallyAdjustsScrollViewInsets = false
You can also edit directly to the attribute inspector:
If anyone of these approaches don't work, by default your UINavigationBar have different heights based on your orientation. For example, the navigation bar is 44 points in portrait and 32 points in landscape.
A workaround can be:
// Create an IBOutlet of your navigationBar height constraint
#IBOutlet weak var navBarHeight: NSLayoutConstraint
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if self.view.bounds.size.height > self.view.bounds.size.width {
self.navBarHeight.constant = 44
} else {
self.navBarHeight.constant = 32
}
}

UIScrollView in UIPopoverController

I am struggling to enable zooming in a UIPopoverController using a UIScrollView. The scrollView is 600x600 and it should display a view controller that displays a UIImageView. The image appears except it's not centered.
This is the code from the viewDidLoad method in the view controller that is displayed in the popover.
- (void)viewDidLoad {
self.imageView = [[UIImageView alloc] init];
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
self.imageView.image = self.image;
self.scrollView = [[UIScrollView alloc] init];
self.scrollView.backgroundColor = [UIColor greenColor];
[self.scrollView setContentSize:self.imageView.image.size];
[self.scrollView setDelegate:self];
[self.imageView setFrame:CGRectMake(0, 0, 600, 600)];
self.view = self.scrollView;
[self.scrollView addSubview:self.imageView];
// Do any additional setup after loading the view.
}
The UIScrollView and UIImageView are declared as properties inside the UIViewController that's displayed in the popover. image is another property that is set to point to an image when the UIViewController is created.
This is what is looks like.
I would like to center the image in the popover and make it fit. How can I do that? Thanks.
what you need to do is:
first:
in your uiviewcontroller which is presented as a popover
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
preferredContentSize = CGSize(width: collectionPreference.bounds.width, height: collectionPreference.bounds.height)
println("I am appearing?")
}
then from the viewcontroller that is presenting the popover:
make it conform to UIPresentationStyleForPresentingController protocol,
and implement this two things:
number one:
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}
number two: in your prepareforsegue method:
if let identifier = segue.identifier {
if identifier == "segueToYourPopoverVC" {
if let pVC = segue.destinationViewController as? YourPopoverVC {
let ppc = pVC.popoverPresentationController
ppc?.delegate = self
}
}
}
best of luck

Custom SearchBar iOS

I am trying to create a Custom SearchBar so that I can
Left Align the search image
Change the corners of textbook to be a little more rounded.
After the image is left aligned, the placeholder text can also be left aligned
Change color of the search text
However, even after subclassing UISearchBar I am unable to achieve what I want and facing following problems:
When debugging, I can see UISearchBar in the view & searchField inside it, but upon iteration on self.subViews and checking if the element is UITextField, I don't get anything. Re-checked and I always get one subView which has different memory address than that of searchbar in debug mode
var customSearchBar:UISearchBar?
var searchField:UITextField?
var button:UIButton?
override func layoutSubviews() {
for subView in self.subviews {
if (subView.isKindOfClass(UITextField)) {
searchField = (subView as! UITextField)
break
}
}
if ((searchField) != nil) {
searchField?.textColor = UIColor.redColor() //Testing if code works?
}
super.layoutSubviews()
}
I don't want to use undocumented ways and have almost tried all the ways I could find here, without any success
Kindly help me. I am using Xcode 7 and iOS 8
1.You can try this code:
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
searchBar.backgroundImage = UIImage()//Without this you can't change background color
searchBar.backgroundColor = UIColor.greenColor()
searchBar.showsCancelButton = true
searchBar.returnKeyType = .Done
searchBar.placeholder = "Test text"
var txtSearchField = searchBar.valueForKey("_searchField")
txtSearchField?.layer.cornerRadius = 15
txtSearchField?.layer.borderWidth = 1.5
txtSearchField?.layer.borderColor = UIColor.orangeColor().CGColor
let image = txtSearchField?.subviews?[1]
image?.frame = CGRect(x: 0, y: 7.5, width: 13, height: 13)
let lbl = txtSearchField?.subviews.last as! UILabel
lbl.textColor = UIColor.whiteColor()
lbl.backgroundColor = UIColor.blueColor()
lbl.frame = CGRect(x: 13, y: 1, width: 127.5, height: 25)
Result from Playground:
Also you can look at this and this open source solutions.
To understand logic of how UISearchBar is build you can have a look on their UISearchBar.h file with all private apis here. As you can see, it has UISearchBarTextField as a subview.
Last year in iOS 7 project I used this code to access UITextField of UISearchBar:
UITextField *searchBarTextField;
for (UIView *subview in self.searchBar.subviews) {
for (UIView *subsubview in subView.subviews){
if ([subsubview isKindOfClass:[UITextField class]]) {
searchBarTextField = (UITextField *)subsubview;
break;
}
}
}
However, I would not recommend to use this logic, as if Apple changes private API method you UI and layout might be broken. You can try to use loop method to loop threw all subviews of subviews of UISearchBar and find needed text field, but again, it might be removed any time.
In the future, if you have any questions on how to access any subview on Apple build UI - you can debugger view hierarchy by pressing this button on debug panel:
If you want to make it custom - why not creating you own one? UIView + UITextField + UIButton + some logic = UISearchBar.

Add extra function when status bar is tapped

I want my navigation bar to unhide when the status bar is tapped. Currently it's only scrolling my webview to the top. Anybody knows how to get this working? The webview can still scroll to top, this function doesn't need to be removed.
Create a UIWindow with the same dimensions as your status bar, add a UIButton to the UIWindow, and position it on top of your status bar.
import UIKit
class ViewController: UIViewController {
let statusbarWindow = UIWindow()
let statusbarButton = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
// Setup UIWindow
statusbarWindow.frame = CGRectMake(0, 0,
UIApplication.sharedApplication().statusBarFrame.size.width,
UIApplication.sharedApplication().statusBarFrame.size.height)
statusbarWindow.windowLevel = UIWindowLevelStatusBar
statusbarWindow.makeKeyAndVisible()
// Setup UIButton
statusbarButton.frame = CGRectMake(0, 0,
UIApplication.sharedApplication().statusBarFrame.size.width,
UIApplication.sharedApplication().statusBarFrame.size.height)
statusbarButton.backgroundColor = UIColor.clearColor()
statusbarButton.addTarget(self, action: "statusbarButton:", forControlEvents: UIControlEvents.TouchUpInside)
statusbarWindow.addSubview(statusbarButton)
}
func statusbarButton(sender:UIButton!) {
// Scroll UIWebView to top
yourWebView.scrollView.contentOffset = CGPoint(0,0)
// Unhide nav bar here
}
Apple Docs: UIWindowLevel, makeKeyAndVisible.

UITableView's subview never shows up

I'm trying to add a subview to UITableView (yes, not UITableViewCell but UITableView). And it is never shown. At first I thought that I add it too early and it gets covered by the cells, but that's not true. I tried to add it with a delay when all cells are already added, i tried bringing it to front, i tried adding the view to tableview's subviews, but all in vain, it just never shows up. Here is my code:
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
override func viewDidAppear(animated: Bool)
{
super.viewDidAppear(animated)
func c()
{
var v:UIView = UIView(frame:CGRectMake(0.0, 0.0, 40.0, 40.0))
v.backgroundColor = UIColor.greenColor()
v.center = CGPointMake(40.0, 40.0)
tableView!.addSubview(v)
tableView!.bringSubviewToFront(v)
}
delay(5.0, closure: c)
}
Any ideas? The problem is obviously related to Swift because in Objective-C it doesn't reproduce
First
I try this in a UITableViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
view.backgroundColor = [UIColor redColor];
[self.view addSubview:view];
}
It works
Second
I notice that you add a view with CGRectMake(0.0, 0.0, 40.0, 40.0). So the view might under the navigation bar if you have one in your viewcontroller

Resources