I'm trying to add scrollbars to an IKImageView. Basically at the moment, I need some examples of a program that loads an image into a view, and if the window is too small, sets up scrollbars that do the right things...
Why can I not find these examples on the apple dev site?
Added info:
After looking at ImagekitDemo I see that evidently I DO need to embed the IKIMageView in a ScrollView. (and somehow that makes the has___Scroller properties of the IKImageView YES...)
However, now (And this is true in ImageKitDemo as well) The scroll bars are fine as long as only one (or neither) is needed. However, as soon as both are needed, and either dimension of the window is smaller than the image, BOTH scrollbars disappear.
Mouse scrolling still works.
ZoomViewController.h
#interface ZoomViewController : UIViewController <UIScrollViewDelegate>
{
ForecastImage* detailImage; // wrapper class around UIImage (optional - could just be UIImage)
IBOutlet UIImageView* imageView;
IBOutlet DoubleTapScrollView* zoomableScrollView;
}
#property (readwrite, nonatomic, retain) ForecastImage* detailImage;
- (IBAction) dismissZoomViewController;
- (UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView;
- (void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale;
#end
ZoomViewController.m
#implementation ZoomViewController
#synthesize detailImage;
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated
{
[imageView setImage:[self.detailImage renderedImage]];
[zoomableScrollView setContentSize:[[imageView image] size]];
[zoomableScrollView setMaximumZoomScale:5.0];
[zoomableScrollView setMinimumZoomScale:0.25];
}
- (void) viewDidAppear:(BOOL)animated
{
self.navigationItem.title = [SearchService getDisplayName:[self.detailImage forecastArea]];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc
{
imageView.image = nil;
self.detailImage = nil;
[super dealloc];
}
- (IBAction) dismissZoomViewController
{
[self dismissModalViewControllerAnimated:YES];
}
#pragma mark Pinch-n-Zoom
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return imageView;
}
- (void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
CGSize newSize = CGSizeMake(imageView.image.size.width * scale, imageView.image.size.height * scale);
[scrollView setContentSize:newSize];
}
#end
The best place to start is the Scroll View Programming Guide. Basically, you need to put the IKImageView inside a NSScrollView. If the IKImageView size exceeds the visible rectangle of the NSScrollView, then scrollbars will appears.
The following sample uses IKImageView to perform various zoom and resizing operations.
Related
i am working on uicollectionview. i want customize cell so i took separate class file for cell. i took an image in cell from storyboard. my problem is i want rounding image but image shape convert to be diamond. please suggest me the way to convert this diamond image into to circle.
see here
UICollectionView in storyboard
ViewController.h
#interface ViewController : UIViewController
#property(nonatomic, weak)IBOutlet UICollectionView *my_collectionview;
#end
ViewController.m
#interface ViewController ()
#end
#implementation ViewController
#synthesize my_collectionview;
- (void)viewDidLoad {
[super viewDidLoad];
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 9;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"CollectionViewCell" forIndexPath:indexPath];
return cell;
}
CollectionViewCell.h
#interface CollectionViewCell : UICollectionViewCell
#property(nonatomic, weak) IBOutlet UIImageView *temp_imgview;
#end
CollectionViewCell.m
-(void)awakeFromNib{
[temp_imgview.layer setCornerRadius:self.temp_imgview.frame.size.width/2];
temp_imgview.layer.borderWidth=0.5;
temp_imgview.layer.masksToBounds = YES;
temp_imgview.clipsToBounds=YES;
}
if i put hard code 100 instead of self.temp_imgview.frame.size.width/2 then it is working. can anybody help me how can i solve this
Depending on your constraints in the storyboard, the awakeFromNib might not be the correct place to all the rounded corners. That is because it might be that the frame of the imageView is not final there.
You could try adding the code for the rounded corners in layoutSubviews. Something like this:
- (void)layoutSubviews {
[super layoutSubviews];
[temp_imgview.layer setCornerRadius:self.temp_imgview.frame.size.width/2];
temp_imgview.layer.borderWidth=0.5;
temp_imgview.layer.masksToBounds = YES;
temp_imgview.clipsToBounds=YES;
}
Also, in your awakeFromNib, you missed the super call.
Let me know if this worked out for you or need more help! Good luck
Update
You could try using the size of the image, instead of the frame. Something like this:
- (void)layoutSubviews {
[super layoutSubviews];
[temp_imgview.layer setCornerRadius:self.temp_imgview.image.size.width/2];
temp_imgview.layer.borderWidth=0.5;
temp_imgview.layer.masksToBounds = YES;
temp_imgview.clipsToBounds=YES;
}
If this does not work either, try logging the frame of your image on iPhone and iPad to see what differs between them
Try adding [self layoutIfNeeded], it worked for me.
- (void)layoutSubviews {
[super layoutSubviews];
[self layoutIfNeeded];
imageView.layer.cornerRadius = CGRectGetWidth(imageView.bounds) / 2;
imageView.layer.borderWidth = 0.1;
imageView.clipsToBounds = YES;
}
In my code, when I set canDisplayBannerAds=YES on my view controller, I get callbacks to viewDidLayoutSubviews when the ad disappears but not when the ad appears. I'm guessing this is because Apple moves the original self.view of the view controller to self.originalContentView when you set canDisplayBannerAds to YES.
My question is, what is a reasonable work around for this?
My solution to this problem is to replace self.view before setting canDisplayBannerAds=YES with a UIView that overrides layoutSubviews.
#protocol LayoutViewDelegate <NSObject>
- (void) layout;
#end
#interface LayoutView : UIView
#property (nonatomic, weak) id<LayoutViewDelegate> delegate;
#end
#implementation LayoutView
- (void) layoutSubviews {
[super layoutSubviews];
if (self.delegate) [self.delegate layout];
}
#end
I do this replacement in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Calendar.viewDidLoad");
// Replace the view, before setting up ads for iOS7, so we can get callbacks for viewDidLayoutSubviews; otherwise, we only get viewDidLayoutSubviews callbacks when ad disappears.
if ([Utilities ios7OrLater]) {
self.layoutView = [[LayoutView alloc] initWithFrame:self.view.frame];
self.view = self.layoutView;
self.layoutView.delegate = self;
}
}
And in viewDidAppear, I do:
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if ([Utilities ios7OrLater]) {
self.canDisplayBannerAds = YES;
}
}
And I add the delegate method:
// This *always* gets called when the banner ad appears or disappears.
#pragma - LayoutViewDelegate method
- (void) layout {
// do useful stuff here
}
#pragma -
I am having some troubles understanding how to wire a custom NSView for an NSMenuItem to support both animation and dragging and dropping. I have the following subclass of NSView handling the bulk of the job. It draws my icon when the application launches correctly, but I have been unable to correctly setup the subview to change when I invoke the setIcon function from another caller. Is there some element of the design that I am missing?
TrayIconView.m
#import "TrayIconView.h"
#implementation TrayIconView
#synthesize statusItem;
static NSImageView *_imageView;
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
statusItem = nil;
isMenuVisible = NO;
_imageView = [[NSImageView alloc] initWithFrame:[self bounds]];
[self addSubview:_imageView];
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
// Draw status bar background, highlighted if menu is showing
[statusItem drawStatusBarBackgroundInRect:[self bounds]
withHighlight:isMenuVisible];
}
- (void)mouseDown:(NSEvent *)event {
[[self menu] setDelegate:self];
[statusItem popUpStatusItemMenu:[self menu]];
[self setNeedsDisplay:YES];
}
- (void)rightMouseDown:(NSEvent *)event {
// Treat right-click just like left-click
[self mouseDown:event];
}
- (void)menuWillOpen:(NSMenu *)menu {
isMenuVisible = YES;
[self setNeedsDisplay:YES];
}
- (void)menuDidClose:(NSMenu *)menu {
isMenuVisible = NO;
[menu setDelegate:nil];
[self setNeedsDisplay:YES];
}
- (void)setIcon:(NSImage *)icon {
[_imageView setImage:icon];
}
TrayIconView.h
#import <Cocoa/Cocoa.h>
#interface TrayIconView : NSView
{
BOOL isMenuVisible;
}
#property (retain, nonatomic) NSStatusItem *statusItem;
- (void)setIcon:(NSImage *)icon;
#end
The solution to this problem was actually outside of the view detailed here. The caller of the interface was being double instantiated on accident, thus nulling out the reference to the previously created NSView. After correcting that concern the app draws and works just fine.
With regard to dragging, I just implemented a subclass of NSView that implemented the Cocoa draggable protocol and added it as a subview to this parent class. That allows dragging onto the currently established NSRect that contains the menubar icon.
I have a UINavigationController and I would like the view of every view controller that is popped onto the stack to have a common padding/margin (e.g. 25 pixels on all sides). What is the best way to accomplish this?
I originally thought that I could implement UINavigationControllerDelegate and inside the navigationController:didShowViewController:animated or navigationController:willShowViewController:animated methods, simply change the frame of the view controller that was about to be displayed. This does not seem to have an effect though.
I tried to do the same thing inside the view controller's viewDidAppear and viewWillAppear methods, but this also did not work. Ideally, I don't want to put any logic in the controllers anyway, as they may not always be used inside a navigation controller.
One last idea that I haven't tried yet is to create a "wrapper" UIViewController that would actually get pushed onto this stack. This wrapper would add the real view controller's view as a subview with a frame that would provide the desired margin. The downside here is that I would need to subclass UINavigationController and override pushViewController:animated, where the wrapper would be initialized and pushed. Apple's documentation indicates that UINavigationController is not meant to be subclassed.
Thanks in advance.
I solved this by putting a "wrapper" UIView around the UIViewController's view instead of the UIViewController itself. The wrapper view then pads the subview by setting the subview's frame in the layoutSubviews method.
I've attached the code I used for convenience. To use, replace your UINavigationController with the PaddedNavigationController, and set the PaddedNavigationController's insets property.
PaddedNavigationController.h:
#import <Foundation/Foundation.h>
#interface PaddedNavigationController : UINavigationController
{
UIEdgeInsets _insets;
}
#property (nonatomic, assign) UIEdgeInsets insets;
#end
PaddedNavigationController.m:
#import "PaddedNavigationController.h"
#interface PaddedView : UIView
{
UIView *_view;
UIEdgeInsets _insets;
}
#property (nonatomic, assign) UIEdgeInsets insets;
+ (PaddedView *) wrapView:(UIView *)view withInsets:(UIEdgeInsets)insets;
- (id) initWithView:(UIView *)view insets:(UIEdgeInsets)insets;
#end
#implementation PaddedNavigationController
#synthesize insets = _insets;
- (void) pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
//check if the UIViewController's view has already been wrapped by the PaddedView; don't want to wrap it twice
if(![viewController.view isKindOfClass:[PaddedView class]])
{
viewController.view = [PaddedView wrapView:viewController.view withInsets:self.insets];
}
[super pushViewController:viewController animated:animated];
}
- (void) setInsets:(UIEdgeInsets)insets
{
_insets = insets;
//loop through this navigation controller's view controllers and set the new insets on any PaddedViews
for(UIViewController *viewController in self.viewControllers)
{
if([viewController.view isKindOfClass:[PaddedView class]])
{
PaddedView *padded = (PaddedView *)viewController.view;
padded.insets = insets;
}
}
}
#end
#implementation PaddedView
#synthesize insets = _insets;
+ (PaddedView *) wrapView:(UIView *)view withInsets:(UIEdgeInsets)insets
{
return [[[PaddedView alloc] initWithView:view insets:insets] autorelease];
}
- (id) initWithView:(UIView *)view insets:(UIEdgeInsets)insets
{
if(self = [super initWithFrame:view.frame])
{
_insets = insets;
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_view = [view retain];
[self addSubview:view];
}
return self;
}
- (void) dealloc
{
[_view release];
[super dealloc];
}
- (void) layoutSubviews
{
//apply the insets to the subview
_view.frame = CGRectMake(self.insets.left, self.insets.top, self.frame.size.width - self.insets.left - self.insets.right, self.frame.size.height - self.insets.top - self.insets.bottom);
}
- (void) setInsets:(UIEdgeInsets)insets
{
_insets = insets;
//we need to re-layout the subviews as the insets have changed
[self layoutSubviews];
}
#end
I'm trying to create programmatically a uiPickerView and add it to a view without using interface builder. Don't get me wrong, I like IB but the reason why I want to do it this way is because i'm trying to build an object that I can quickly plug in to produce popup menus using UIPopoverViewController and a variety of different subViews (such as uiPickerView) as the menu in the popup. I've already made this work by building the menu in IB and initializing the popup with its ViewController so I know how this works for the most part.
I've entered the relevant code below and this is the two errors I get when I run it:
- "Could not find mapped image UIPickerViewFrameRight-162-Popover.png"
- "Could not find mapped image UIPickerViewFrameLeft-162-Popover.png"
I don't know what these images are but I'm assuming they are the png's of the picker view.
menu = [[UIPickerView alloc]initWithFrame:CGRectMake(0,100,162,162)];
menu.delegate = self;
menu.dataSource = self;
[menu reloadAllComponents];
[menu selectRow:0 inComponent:0 animated:YES];
//Add the picker to the view
[customViewController.view addSubview:menu];
popView = [[UIPopoverController alloc] initWithContentViewController:customViewController] ;
[popView setDelegate:self];
CGRect pos = [rootView frame];
[popView presentPopoverFromRect:CGRectMake(pos.origin.x,pos.origin.y,0,pos.size.height)
inView:displayView permittedArrowDirections:arrowDir animated:YES];
Now this Code will crash the program unless you remove the line where I try to add the picker to the view, at which point I just get the blank popover. So I know that it is the picker that is causing this issue however I don't know how to fix it. I've been searching all day but every tutorial online on uipickers all include using IB. My guess is that this is a really stupid error like missing an import or something but if anyone can tell me what I'm doing wrong it would be greatly appreciated.
Also note that I followed the tutorials on how to set up the dataSource and delegate methods for the UIPickerView and I'm pretty sure they are fine however if you want to verify here you are: Thanks again.
#import "PopUpMenuViewController.h"
#implementation PopUpMenuViewController
#synthesize menuType;
#synthesize data;
#synthesize popView;
#synthesize menu;
#synthesize customViewController;
#pragma mark -
#pragma mark UIPOPOVERCONTROLLER DELEGATE METHODS
#pragma mark -
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController{
//Delegate this too the User of this class
return TRUE;
}
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController{
//Delegate this too the User of this class
}
#pragma mark -
#pragma mark CUSTOM POPOVERVIEWCONTROLLER METHODS
#pragma mark -
-(void) initWithMenuType:(int)type{
menuType = type;
}
-(id) initWithMenuType:(int)type andData:(NSMutableArray *)dataSet fromViewItem:(id)sender
withMainView:(UIView *)mView{
[super init];
menuType = type;
data = dataSet;
rootView = sender;
displayView = mView;
arrowDir = UIPopoverArrowDirectionUp;
customViewController = [[UIViewController alloc] initWithNibName:#"PopUpMenu" bundle:nil];
return self;
}
-(void) setPopUpArrowDirection:(UIPopoverArrowDirection) arrow{
arrowDir = arrow;
}
-(void) showPopUp{
//UIPicker Menu
if (menuType==1) {
//UIPicker Setup
menu = [[UIPickerView alloc]initWithFrame:CGRectMake(0,100,162,162)];
menu.delegate = self;
menu.dataSource = self;
[menu reloadAllComponents];
[menu selectRow:0 inComponent:0 animated:YES];
//Add the picker to the view
[customViewController.view addSubview:menu];
popView = [[UIPopoverController alloc] initWithContentViewController:customViewController] ;
[popView setDelegate:self];
CGRect pos = [rootView frame];
[popView presentPopoverFromRect:CGRectMake(pos.origin.x,pos.origin.y,0,pos.size.height)
inView:displayView permittedArrowDirections:arrowDir animated:YES];
//[popView setPopoverContentSize:CGSizeMake(menu.frame.size.width+5,menu.frame.size.height+5)];
}
}
#pragma mark -
#pragma mark VIEW CONTROLLER DELEGATE METHODS
#pragma mark -
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
/*
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization.
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
}*/
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return YES;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
[data release];
[popView release];
[menu release];
[rootView release];
[displayView release];
[customViewController release];
}
#pragma mark -
#pragma mark UIPICKERVIEW DELEGATE & DATASOURCE METHODS
#pragma mark -
#pragma mark -
#pragma mark UIPickerViewDataSource Methods
- (NSInteger) pickerView: (UIPickerView *) pickerView numberOfRowsInComponent: (NSInteger) component {
return [data count];
}
- (NSInteger) numberOfComponentsInPickerView: (UIPickerView *) pickerView {
return 1;
}
#pragma mark -
#pragma mark UIPickerViewDelegate Methods
// Row height in pixels
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component {
return 40.0f;
}
// Column width in pixels
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component {
return 90.0f;
}
- (NSString *) pickerView: (UIPickerView *) pickerView titleForRow: (NSInteger) row
forComponent: (NSInteger) component {
return [data objectAtIndex:row];
}
- (void) pickerView: (UIPickerView *) pickerView
didSelectRow: (NSInteger) row inComponent: (NSInteger) component {
}
If anyone else encounters this particular warning in the console "Could not find mapped image UIPickerViewFrameRight-162-Popover.png", I think I've figured out why it appears.
The HIG indicates loosely that UIPickerView should only be added to a Popover on the iPad.
"On iPad, present a date and time picker only within a popover."
http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/mobilehig/UIElementGuidelines/UIElementGuidelines.html
In my experiments, the UIPickerView must be the direct and only view of the current UIViewController in a popover. If the UIPickerView appears elsewhere in a view hierarchy, the warning appears and the UIPickerView will look bad (like it's missing the left and right portions of the view).
In the code above, you can see that the UIPickerView was added as a subview of the rootView in the customController:
[customViewController.view addSubview:menu];
This probably would have worked if the UIPickerView was the root view in the customController.
You can programmatically make the UIPickerView the root view of the controller by overriding the loadView method of the controller and assigning the UIPickerView directly to the root view of the controller:
- (void)loadView {
CGRect frame = CGRectMake(0,0, 300, 300);
UIPickerView *v = [[[UIPickerView alloc] initWithFrame:frame] autorelease];
v.delegate = self; // assuming controller adopts UIPickerViewDelegate
v.dataSource = self; // assuming controller adopts UIPickerViewDataSource
self.view = v;
}
Hope this helps someone.
Alright well I'm not quite sure what happened but I deleted the project and re-wrote this code and voila... No more issues.
I just recently ran into the same issue with my app on the iPad and iPhone. It actually was a simple but stupid fix which involved making the height on the iPad to 180 and 162 on the iPhone. God must love apple s/w but I don't.