so i have a navigation controller, and in it i have a view and a scrollview embedded in that view. My goal is to make my program scroll to a location when it is close to it.
to do this i added to outlets to my vc. one is the scroll view and the other is the view. The view is just a big rectangle about twice as wide as the iphones screen and slightly higher. My scroll view scrolls only horizantally, and whenever i lift my finger from scrolling, my goal is if the iphones bounds are within the views bounds. I want the scroll view to manually scroll to the middle of that view. (if you can think of a game menu in angry birds or cut the rope, when the user is scrolling between level packs horizantally, when the user lets go from scrolling it sort of zaps into place to the level the user let go by, this is what i want to mimick).
so, heres my code for both my view and my vc. The only thing i did with storyboards is that i hooked up the two outlets, and set the size of my view.
(the level packs is the vc and the other one is the view).
#import <UIKit/UIKit.h>
#import "HorizantalLockingView.h"
#interface LevelPacks : UIViewController <ViewDelegate>
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
#property (weak, nonatomic) IBOutlet HorizantalLockingView *lockingView;
#end
#import "LevelPacks.h"
#implementation LevelPacks
#synthesize scrollView=_scrollView;
#synthesize lockingView = _lockingView;
-(void)viewDidAppear:(BOOL)animated
{
CGSize size;
size.width=825;
size.height=460;
self.scrollView.contentSize=size;
self.scrollView.contentOffset=CGPointMake(0, 0);
}
-(void)viewDidLoad
{
[super viewDidLoad];
self.lockingView.delegate=self;
}
- (void)viewDidUnload
{
[self setLockingView:nil];
[super viewDidUnload];
self.scrollView=nil;
// Release any retained subviews of the main view.
}
#end
#import <UIKit/UIKit.h>
#protocol ViewDelegate
#property (nonatomic, weak) UIScrollView *scrollView;
#end
#interface HorizantalLockingView : UIView
#property (nonatomic, weak) IBOutlet id <ViewDelegate> delegate;
#end
#import "HorizantalLockingView.h"
#implementation HorizantalLockingView
#synthesize delegate=_delegate;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGRect location=self.superview.bounds;
NSLog(#"dkfjdkjf");
if (CGRectContainsRect(self.frame, location))
{
[self.delegate.scrollView scrollRectToVisible:CGRectMake(284, 190, 157, 119) animated:YES];
}
}
#end
o, and i did the nslog earlier to see if the method would even do anything, and the nslog never even ran, so obviously somethings wrong.
Im kind of new to this, any help would really be great!
Enabling paging will automatically do this for you.
scrollView.pagingEnabled=YES;
Also adding a UIPageControl and using the UIScrollView delegate methods to update the page control will add a good usability
Related
Is it possible to have an MKMapView lined up on top of another MKMapView with the top having a level of transparency so you can see the bottom. Further when the user swipes, I would like BOTH the top and bottom map to scroll, or zoom in unison.
I am finding the standard map too plain and the satellite map too intense and was hoping to combine them for effect.
Any thoughts?
You can do this, no problem at all. As you already described, just put a MKMapView in your window and a second one on top. Let's assume we call them _map1 and _map2, the latter being on top of _map1. The MKMapViewDelegate protocol will let you know when a user scrolls/moves/zooms _map2, so you can tell _map1 to display the same visible region of _map2.
In my example I use a slider to set the level of transparency of _map2.
#import "ViewController.h"
#import MapKit;
#interface ViewController () <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *map1;
#property (weak, nonatomic) IBOutlet MKMapView *map2;
#property (weak, nonatomic) IBOutlet UISlider *alphaSlider;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[_map1 setMapType:MKMapTypeSatellite];
[_map2 setMapType:MKMapTypeStandard];
[_map2 setAlpha:0.5];
[_map2 setDelegate:self];
[_alphaSlider addTarget:self action:#selector(sliderChanged) forControlEvents:UIControlEventAllEvents] ;
_alphaSlider.value = _map2.alpha;
}
- (void)mapViewDidChangeVisibleRegion:(MKMapView *)mapView
{
// _map2 is on top and will receive visible region updates, i.e. the user scrolled/moved/zoomed the map
// just pass the new region to _map1 so it will be similar to that one of _map2
[_map1 setRegion:_map2.region];
}
- (void)sliderChanged
{
[_map2 setAlpha:_alphaSlider.value];
}
I have two text views beside each other with multiple lines of text.
How can I make them both scroll together based on scrolling either one of them at the same time?
First
#interface ViewController : UIViewController <UITextViewDelegate>
second make both textViews delagates
tv1.delegate = self
tv2.delegate = self
Implement
-(void)scrollViewDidScroll:(UIScrollView *)inScrollView {
self.tv1.contentOffset = inScrollView.contentOffset;
self.tv2.contentOffset = inScrollView.contentOffset;
}
Here is a demo txView
Edit
.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITextViewDelegate>
#property (weak, nonatomic) IBOutlet UITextView *tv1;
#property (weak, nonatomic) IBOutlet UITextView *tv2;
#end
.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.tv1.delegate = self;
self.tv2.delegate = self;
}
- (void)scrollViewDidScroll:(UIScrollView *)inScrollView {
self.tv1.contentOffset = inScrollView.contentOffset;
self.tv2.contentOffset = inScrollView.contentOffset;
}
I'm relatively new to Xcode, and am in the process of making an app in Objective C with several viewControllers each with a single UIScrollView containing a single UIImage that can be zoomed and scrolled.
This code works for the first image (dermatomes), but I can't figure out how to tweak the UIView to enable zooming and scrolling on the second image (anatomicPlanes). Currently the second image imports correctly to the second UIScrollView, but when I try to zoom it just jumps down and right and remains static there.
The size of the UIScrollViews were set using Interface Builder, no problems there.
viewController.h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UIScrollViewDelegate> {
IBOutlet UIScrollView *dermatomeScrollView;
UIImageView *dermatomesImageView;
IBOutlet UIScrollView *anatomicPlaneScrollView;
UIImageView *anatomicPlanesImageView;
}
#property (strong, nonatomic) IBOutlet UIScrollView *dermatomeScrollView;
#property (strong, nonatomic) IBOutlet UIImageView *dermatomesImageView;
#property (strong, nonatomic) IBOutlet UIImageView *anatomicPlanesImageView;
#property (strong, nonatomic) IBOutlet UIScrollView *anatomicPlaneScrollView;
#end
viewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize dermatomeScrollView, anatomicPlanesImageView, dermatomesImageView, anatomicPlaneScrollView;
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return dermatomesImageView;
}
- (void)viewDidLoad {
[super viewDidLoad];
UIImageView *dermatomes = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:#"dermatomes.jpg"]];
self.dermatomesImageView = dermatomes;
dermatomeScrollView. maximumZoomScale = 1.2;
dermatomeScrollView. minimumZoomScale = 0.4;
dermatomeScrollView. delegate = self;
[dermatomeScrollView addSubview:dermatomesImageView];
dermatomeScrollView.zoomScale = 0.6;
UIImageView *planes = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:#"anatomic planes.jpg"]];
self.anatomicPlanesImageView = planes;
anatomicPlaneScrollView. maximumZoomScale = 1.2;
anatomicPlaneScrollView. minimumZoomScale = 0.4;
anatomicPlaneScrollView. delegate = self;
[anatomicPlaneScrollView addSubview:anatomicPlanesImageView];
anatomicPlaneScrollView.zoomScale = 0.6;
}
Any help is appreciated!
You need to return the correct view based on the scroll view that is requesting. Every method in the delegate pattern is passed a reference to the originator of the method call, so your delegate implementation can handle it differently. In this case, the originator of the delegate method call is the scroll view:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
if (scrollView == dermatomeScrollView) {
return dermatomesImageView;
}
return anatomicPlanesImageView;
}
If you add more scrollviews, you'll have to extend this method further.
In my iOS application, I have a main View Controller with three buttons, which work like a tab bar: when I click one of the buttons, a new view controller is invoked.
I tried to implement this via container view containers, so I tried following this guide (http://www.thinkandbuild.it/working-with-custom-container-view-controllers/) and invoke the presentDetailController method in the viewDidLoad of the main controller.
Actually, no views are showed: someone can help me figuring out why? Thanks.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIButton *btnOne;
#property (weak, nonatomic) IBOutlet UIButton *btnTwo;
#property (weak, nonatomic) IBOutlet UIButton *btnThree;
#property (weak, nonatomic) IBOutlet UIView *detailView;
- (IBAction)click:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#import "FirstViewController.h"
#interface ViewController ()
#property UIViewController *currentDetailViewController;
#end
#implementation ViewController
#synthesize btnOne, btnTwo, btnThree;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
FirstViewController *fvc = [[FirstViewController alloc]initWithString:#"I'm the first Controller!"];
[self presentDetailController:fvc];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)click:(id)sender
{
// button selection stuff
[self addDetailController:sender];
}
- (void)presentDetailController:(UIViewController*)detailVC{
//0. Remove the current Detail View Controller showed
if(self.currentDetailViewController){
[self removeCurrentDetailViewController];
}
//1. Add the detail controller as child of the container
[self addChildViewController:detailVC];
//2. Define the detail controller's view size
detailVC.view.frame = [self frameForDetailController];
//3. Add the Detail controller's view to the Container's detail view and save a reference to the detail View Controller
[self.detailView addSubview:detailVC.view];
self.currentDetailViewController = detailVC;
//4. Complete the add flow calling the function didMoveToParentViewController
[detailVC didMoveToParentViewController:self];
}
- (void)removeCurrentDetailViewController{
//1. Call the willMoveToParentViewController with nil
// This is the last method where your detailViewController can perform some operations before neing removed
[self.currentDetailViewController willMoveToParentViewController:nil];
//2. Remove the DetailViewController's view from the Container
[self.currentDetailViewController.view removeFromSuperview];
//3. Update the hierarchy"
// Automatically the method didMoveToParentViewController: will be called on the detailViewController)
[self.currentDetailViewController removeFromParentViewController];
}
- (CGRect)frameForDetailController{
// newFrame's height should be currentFrame's height minus buttons' height
CGRect detailFrame = CGRectMake(0, 0, self.detailView.bounds.size.width, self.detailView.bounds.size.height-self.btnOne.frame.size.height);
return detailFrame;
}
- (void)addDetailController:(id)sender {
FirstViewController *detailVC = [[FirstViewController alloc]initWithString:#"First button clicked"];
[self presentDetailController:detailVC];
}
#end
FirstViewController.h
#import <UIKit/UIKit.h>
#class ViewController;
#interface FirstViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (weak, nonatomic) IBOutlet UIButton *btnOne;
#property (weak, nonatomic) IBOutlet UIButton *btnTwo;
#property (weak, nonatomic) IBOutlet UIButton *btnThree;
- (id)initWithString:(NSString*)string;
#end
FirstViewController.m
#import "FirstViewController.h"
#interface FirstViewController (){
NSString *text;
}
#end
#implementation FirstViewController
- (id)initWithString:(NSString*)string {
self = [super init];
if(self){
text = string;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.label.text = text;
}
#end
As part of creating FirstViewController, you are calling [super init] which produces a bare UIViewController. From your diagram, it seems as if you want to load a FirstViewController from your storyboard instead.
I suggest a sequence where you create your controller using instantiateViewControllerWithIdentifier:, then set a string property in the controller that you want to use as the label, and finally assign the string to the label when the controller's view loads.
I have looked around many different threads over the same issue and can't seem to grasp what is going on here. I created a very basic and simple project. What I want to happen is for a bunch of elements to be inside of a scroll view that scrolls properly. These elements may include a UITableView that scrolls independently (or not). Here is how I set up my basic project:
Running this in the simulator will result in a view that doesn't scroll. This is expected as there is more than enough room for all of the elements. I then changed the size of UIScrollView like so:
Running this in the simulator results in a smaller view that will not scroll. I assume I am not doing this the correct way. Here is the code I have most recently tried:
ViewController.h
#interface ViewController : UIViewController <UIScrollViewDelegate>
#property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
#property (strong, nonatomic) IBOutlet UIButton *buttonOne;
#property (strong, nonatomic) IBOutlet UIButton *buttonTwo;
#property (strong, nonatomic) IBOutlet UIButton *buttonThree;
#property (strong, nonatomic) IBOutlet UIButton *buttonFour;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.buttonOne setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.buttonTwo setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.buttonThree setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.buttonFour setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Any help would be greatly appreciated.
The problem is that when you change the size of the scroll view in interface builder, you are also setting the content's size to the same as the frame size.
You can manually increase the content size of the scroll view in code so that you can scroll it like this:
// scrollView is an outlet to your scroll view
// Add 200 points to the bottom of the scroll view
[self.scrollView setContentInset:UIEdgeInsetsMake(0, 0, 200, 0)];
Though, you probably don't need to do this as long as you draw the sub view at full size, and make it a sub view of some other view, and let it automatically re-size itself.