How i can add header like this inside my app and receive the touch event also control over it to hide/show ?
Here is something to work on.
I made a new project for iOS 7, with a single ViewController. Here is the storyboard :
I added a simple UIView at the top, a UINavigationBar just under it, and a large UIView taking the remaining space. This last view is where you should put your content.
Now here is the ViewController code :
ViewController.h :
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIView *littleView;
#property (weak, nonatomic) IBOutlet UINavigationBar *navBar;
#property (weak, nonatomic) IBOutlet UIView *mainView;
- (IBAction)toggleLittleView:(id)sender;
#end
littleView is the view behind the status bar, navbar is the navigation bar, mainView is the content view, and toggleLittleview is linked to the button in the nav bar.
ViewController.m :
#implementation ViewController {
BOOL isVisible;
CGFloat statusBarOffset;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Setting initial values
isVisible = YES;
statusBarOffset = 20;
// Adding a gesture recognizer to littleView
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
tap.numberOfTapsRequired = 1;
tap.numberOfTouchesRequired = 1;
[_littleView addGestureRecognizer:tap];
}
// Linked to the nav bar button
- (IBAction)toggleLittleView:(id)sender {
// If littleView is not on screen, show it before animation
if (!isVisible) {
_littleView.hidden = !_littleView.hidden;
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}
// Animate to the new frames
[UIView animateWithDuration:0.25
animations:^{
_littleView.frame = CGRectOffset(_littleView.frame, 0, isVisible ? -(_littleView.frame.size.height-statusBarOffset) : (_littleView.frame.size.height-statusBarOffset));
_navBar.frame = CGRectMake(_navBar.frame.origin.x, _littleView.frame.origin.y + _littleView.frame.size.height, _navBar.frame.size.width, _navBar.frame.size.height);
CGFloat offSet = isVisible ? self.view.frame.size.height - _navBar.frame.size.height + statusBarOffset : self.view.frame.size.height - _navBar.frame.size.height - _littleView.frame.size.height + statusBarOffset;
_mainView.frame = CGRectMake(_mainView.frame.origin.x, _navBar.frame.origin.y + _navBar.frame.size.height, _mainView.frame.size.width, offSet);
isVisible = !isVisible;
}
completion:^(BOOL finished) {
// If view is not visible after animation, hide it
if (!isVisible) {
_littleView.hidden = !_littleView.hidden;
[[UIApplication sharedApplication] setStatusBarStyle: UIStatusBarStyleDefault];
}
}];
}
// Do stuff on tap
-(void)handleTap:(UIGestureRecognizer*)tap {
[[[UIAlertView alloc] initWithTitle:#"Test" message:#"You tapped !" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
}
#end
WARNING
This code is not perfect, but it basically replicates the effect you're looking for. You should work on it to make it behave as you wish. Also, this was implemented in a simple UIViewController, not embed in a UINavigationController, with a navigation bar I added manually. This code won't work in a UITableViewController or a UIViewController embed in a UINavigationController. It does not use autolayout, which you definitely should use under iOS 6/7.
Here is gif preview :
Related
i Am using Mb Progress Bar. in which the progress bar is sccessing automatically. here i want to move the progress bar with my mouse cursor.
i am using Github Library
https://github.com/matibot/MBCircularProgressBar
This library gives me animated progress bar which runs automatically on button click. i want exactly this one. but it should not be automatically. i want to move it by my cursor like hand moment.
this is my code:::
#property (weak, nonatomic) IBOutlet MBCircularProgressBarView *progressBar;
#property (weak, nonatomic) IBOutlet UISwitch *animatedSwitch;
#end
#implementation MBViewController
- (void)viewDidLoad {
[super viewDidLoad];
// pan gesture detects circle dragging
UIPanGestureRecognizer *pv = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
//[self addGestureRecognizer:pv];
[self.progressBar addGestureRecognizer:pv];
}
- (IBAction)animate:(UIButton *)sender {
[UIView animateWithDuration:self.animatedSwitch.on * 1.f animations:^{
self.progressBar.value = 100.f - self.progressBar.value;
}];
}
# pragma mark detect pan and determine angle of pan location vs. center of circular revolution
- (void) handlePan:(UIPanGestureRecognizer *)pv {
self.progressBar.value = 100.f - self.progressBar.value;
}
Anyone can have idea. please help me for this::
I have a parent VC with 3 children - Settings, Location and Diary.
Settings, Location & Diary are all accessed via IBActions based on their respective buttons.
When I go between Location and Diary, everything is fine. When I click Settings, it works, but when I click back to Location or Diary I get the dreaded must have a common parent view controller error. Funny thing is the exception says that the Diary and Location VC's don't share the same parent even though in that case I am clicking between Settings and either Diary or Location.
.m properties
#interface LPMainContentViewController ()
#property (weak, nonatomic) IBOutlet UIView *containerView;
#property (weak, nonatomic) IBOutlet UIButton *locationButton;
#property (weak, nonatomic) IBOutlet UIButton *diaryButton;
#property (weak, nonatomic) IBOutlet UIButton *settingsButton;
#property (strong, nonatomic) UIViewController *locationViewController;
#property (strong, nonatomic) UIViewController *diaryViewController;
#property (strong, nonatomic) UIViewController *settingsController;
- (IBAction)goToLocationView:(UIButton *)sender;
- (IBAction)goToDiaryView:(UIButton *)sender;
- (IBAction)goToSettings:(UIButton *)sender;
#end
I use if statements in the code to determine which was the previous child VC for the transition method and to set enabled on the button to YES or NO.
- (IBAction)goToLocationView:(UIButton *)sender {
if ([_diaryViewController isViewLoaded]){
[self cycleFromViewController:_diaryViewController toViewController:_locationViewController];
_locationButton.enabled = NO;
_diaryButton.enabled = YES;
}
else if ([_settingsController isViewLoaded]){
[self cycleFromViewController:_settingsController toViewController:_locationViewController];
_locationButton.enabled = NO;
_settingsButton.enabled = YES;
}
}
- (IBAction)goToDiaryView:(UIButton *)sender {
if ([_locationViewController isViewLoaded]){
[self cycleFromViewController:_locationViewController toViewController:_diaryViewController];
_locationButton.enabled = YES;
_diaryButton.enabled = NO;
}
else if ([_settingsController isViewLoaded]){
[self cycleFromViewController:_settingsController toViewController:_diaryViewController];
_diaryButton.enabled = NO;
_settingsButton.enabled = YES;
}
}
- (IBAction)goToSettings:(UIButton *)sender {
if ([_locationViewController isViewLoaded]){
[self cycleFromViewController:_locationViewController toViewController:_settingsController];
_locationButton.enabled = YES;
_settingsButton.enabled = NO;
}
else if ([_diaryViewController isViewLoaded]){
[self cycleFromViewController:_diaryViewController toViewController:_settingsController];
_diaryButton.enabled = YES;
_settingsButton.enabled = NO;
}
}
and here's the transition method pulled straight from the Apple docs
- (void) cycleFromViewController: (UIViewController*) oldVC
toViewController: (UIViewController*) newVC
{
[oldVC willMoveToParentViewController:nil];
[self addChildViewController:newVC];
newVC.view.frame = _containerView.bounds;
CGRect endFrame = _containerView.bounds;
[self transitionFromViewController: oldVC toViewController: newVC
duration: 0.0 options:0
animations:^{
newVC.view.frame = oldVC.view.frame;
oldVC.view.frame = endFrame;
}
completion:^(BOOL finished) {
[oldVC removeFromParentViewController];
[newVC didMoveToParentViewController:self];
}];
}
isViewLoaded is the wrong thing to check. The view will get loaded once and then stick around, so you're probably choosing the wrong "current" view controller after a few cycles. Have another property to hold the current view controller instead, it will simplify your code and also actually work:
#property (weak, nonatomic) UIViewController *currentViewController;
You'll need to set this to whatever the initial child view controller is when you first set up the container view controller.
Then, change the goToXX methods to be like the following:
- (IBAction)goToDiaryView:(UIButton *)sender {
self.settingsButton.enabled = YES;
self.locationButton.enabled = YES;
self.diaryButton.enabled = NO;
[self cycleFromViewController:self.currentViewController toViewController:self.diaryViewController];
}
Last of all, in your cycle method, make sure you keep this property updated in the completion block of the transition:
completion:^(BOOL finished) {
[oldVC removeFromParentViewController];
[newVC didMoveToParentViewController:self];
self.currentViewController = newVC;
}];
Note that it is safer to use your properties rather than the _instanceVariables. That's what they're there for.
I want to add a UISearchBar to the bottom of my UINavigationBar and I want to make it look like it is a part of the bar. In the video below it shows a default animation of the nav bar sliding into the view from the top. I want to slide in the search bar just before that and make it look like one object.
How can I re-create this animation for a UISearchBar for the showing and hiding animation? And make it seamlessly animate?
Animation
I think you use a custom animation for navigation bar not default animation.
My test code is following.
#import "ViewController.h"
#interface ViewController ()
// Add a UISearchBar below navigation bar in Interface Builder
#property (weak, nonatomic) IBOutlet UISearchBar *searchBar;
#end
#implementation ViewController{
// this is flag for navigation bar status (shown or hidden)
BOOL _isNaviBarHidden;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_isNaviBarHidden = NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// trigger for show navigation bar. I don't know when you want to show. so I add a button in my test viewcontroller
- (IBAction)showNavibar:(id)sender {
if(_isNaviBarHidden == NO){
return;
}
[self setNavibarAndSearchBarHidden:NO];
}
- (IBAction)hideNavibar:(id)sender {
if(_isNaviBarHidden == YES){
return;
}
[self setNavibarAndSearchBarHidden:YES];
}
-(void)setNavibarAndSearchBarHidden:(BOOL)hidden{
CGFloat yOffset = -130;
CALayer *naviBarLayer = self.navigationController.navigationBar.layer;
CALayer *searchBarLayer = self.searchBar.layer;
[UIView animateWithDuration:0.3 animations:^{
if(hidden){
naviBarLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransformMakeTranslation(0, yOffset));
searchBarLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransformMakeTranslation(0, yOffset));
}else{
naviBarLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransformIdentity);
searchBarLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransformIdentity);
}
} completion:^(BOOL finished) {
_isNaviBarHidden = hidden;
}];
}
I need a ViewController to be called modally to show some UIButton and other UIView on top of the current window. I want the background to be partially transparent and showing the current window below it - something similar to a UIActionSheet but with a custom design. I coded my VC to do the following: 1) during init the VC sets self.view.frame equals to [[UIApplication sharedApplication]keyWindow].frame 2) when show() is called the VC adds self.view on top of [[UIApplication sharedApplication]keyWindow] subViews 3) when an internal button calls the private method release() the VC remove self.view from its superview. Example with a single release button as follows:
#implementation ModalController
- (id)init
{
self = [super init];
if (self){
//set my view frame equal to the keyWindow frame
self.view.frame = [[UIApplication sharedApplication]keyWindow].frame;
self.view.backgroundColor = [UIColor colorWithWhite:0.3f alpha:0.5f];
//create a button to release the current VC with the size of the entire view
UIButton *releaseMyselfButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[releaseMyselfButton setTitle:#"Release" forState:UIControlStateNormal];
releaseMyselfButton.frame = CGRectMake(0, 0, 90, 20);
[releaseMyselfButton addTarget:self action:#selector(releaseMyself) forControlEvents:UIControlEventTouchDown];
//add the button to the view
[self.view addSubview:releaseMyself];
}
return self;
}
- (void) show
{
//add self.view to the keyWindow to make sure that it will appear on top of everything else
[[[UIApplication sharedApplication]keyWindow] addSubview:self.view];
}
- (void)releaseMyself
{
[self.view removeFromSuperview];
}
#end
If I create an instance of ModalController from another VC and I call show() everything goes as expected:
#interface CurrentVC ()
#property (strong, nonatomic) ModalController *myModalController;
#end
#implementation CurrentVC
- (void)viewDidLoad
{
[super viewDidLoad];
self.myModalController = [[ModalController alloc]init];
[self.myModalController show];
}
#end
To make it work I need to retain the ModalController in a property until release () is called. However I would like to have the same freedom I have with UIActionSheet and simply keep an instance of it in a local variable:
#implementation CurrentVC
- (void)viewDidLoad
{
[super viewDidLoad];
ModalController *myModalController = [[ModalController alloc]init];
[myModalController show];
}
#end
If I do this with the current code ARC will release myModalController straight after show() is called and the release button will be pointing to nil. How can I make this work without storing the object in a property? I've identified a work around but I'm not sure it's a good design option:
#interface ModalController ()
#property (strong, nonatomic) ModalController *myselfToAutorelease;
#implementation ModalController
- (id)init
{
self = [super init];
if (self){
... ... ...
self.myselfToAutorelease = self;
}
return self;
}
- (void) show
{
... ... ...
}
- (void)releaseMyself
{
[self.view removeFromSuperview];
self.myselfToAutorelease = nil;
}
What I've done is making ModalController "self sufficient" - it stores a pointer to itself during init and set it to nil when it's ready to release himself. It works but I have the feeling that this is against the ARC design principles! Is this approach correct? If not, how can I handle this differently?
Thanks in advance for your help.
Doesn't work like that.
You don't keep a reference to self.
In the main view controller you just create your object. If you need it to be around longer keep it in a property in the main view controller , when done, set the property to nil in the main view controller.
I have UITextFields in tableviewcells. When you swipe over the cell not part of the textfield, the delete action comes up as expected. If you swipe over the textfield, it stops the delete from popping up.
How do I fix this so that you can swipe over the inputs and the cell will trigger the delete action?
I think the issue here is that the touch on the text field is interfering with your swipe gesture recognizer (presumably attached to the parent view). I had a similar problem with a text field that was placed in a UIScrollView.
I got around this problem by overlaying a clear UIView on top of my UITextField. I then assigned a UITapGestureRecognizer to this clear view to set the text field as the first responder when the user taps on the field. Otherwise, the swiped is sent to the parent view (a scroll view) which recognizes the swipe without any issues. It's kind of lame but it works.
This scenario is a bit different from yours, but I think it's the same problem. Here is what my code looks like, hopefully it helps:
// UIView subclass header
#interface LSAddPageView : UIView
#property (weak, nonatomic) IBOutlet UITextField *textField; // Connected to the UITextField in question
#property (strong, nonatomic) UIView *textFieldMask;
#property (assign, nonatomic) BOOL textFieldMaskEnabled;
#end
// UIView subclass implementation
#implementation LSAddPageView
- (void)awakeFromNib
{
[super awakeFromNib];
_textFieldMask = [UIView new];
_textFieldMask.backgroundColor = [UIColor clearColor];
[self insertSubview:_textFieldMask aboveSubview:self.textField];
}
- (void)layoutSubviews
{
[super layoutSubviews];
_textFieldMask.frame = self.textField.frame;
}
- (BOOL)textFieldMaskEnabled
{
return _textFieldMask.hidden == NO;
}
- (void)setTextFieldMaskEnabled:(BOOL)textFieldMaskEnabled
{
_textFieldMask.hidden = !textFieldMaskEnabled;
}
#end
And then in the controller:
- (void)viewDidLoad
{
[super viewDidLoad];
_addPageView = (LSAddPageView*)self.view;
_maskGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(didTapMask:)];
_maskGestureRecognizer.numberOfTapsRequired = 1;
_maskGestureRecognizer.numberOfTouchesRequired = 1;
[_addPageView.textFieldMask addGestureRecognizer:_maskGestureRecognizer];
self.textField.delegate = self; // Set delegate to be notified when text field resigns first responder
}
- (void)didTapMask:(UIGestureRecognizer*)recognizer
{
_addPageView.textFieldMaskEnabled = NO;
[self.textField becomeFirstResponder];
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
_addPageView.textFieldMaskEnabled = YES;
return YES;
}
Sounds like you need to set the cancelsTouchesInView property
yourGestureRecognizer.cancelsTouchesInView = NO;
from UIButton & UITextField will block UITableViewCell being swipe to delete
self.tableView.panGestureRecognizer.delaysTouchesBegan = YES;
this will make the textfield not stop left swipe guestures