I would like to know the best way/correct way to achieve from following layout? I want to place an UIImageView outside of UITableViewCell in a UITableView with static cells.
I have done the following by subclassing UITableViewCell for the cells in section 1 using the following code
- (void)setFrame:(CGRect)frame {
frame.size.width -= 125.0;
[super setFrame:frame];
}
In the UITableViewController's viewDidLoad I add the UIImageView and position it according to the width of the custom UITableViewCell.
This sort of works, but i'm not sure how to deal with rotation and also if what i've done so far would be the correct way?
there are differnt ways to do it. one is to set the width of table view less as you showd in pic 2nd is to use custom table view cell and on required cell add image so that your cell data as well as image will be shown. i think custom cell would be the better solution. tell me if you are asking the same thing what i answered, if no, then i review my answer thank.
I managed to produce what I wanted using the follow, this is proberly not the best way or cleanest way but as no one from StackOverFlow gave any better suggestions I thought I better answer this.
I subclassed the first 3 UITableViewCells and set a frame size to take into account the size of my image.
- (void)setFrame:(CGRect)frame {
float cellWidth = (frame.size.width - 345);
frame.size.width = cellWidth;
[super setFrame:frame];
}
Then in my UITableViewController's viewDidLoad I create and position the UIImageView using the first static cell in the tableview as an IBOutlet ("firstCell"). I then set the autoResizingMask which sorts out rotation and finally add the UIImageView to the view.
//Create and position the image view
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake((firstCell.frame.size.width), (firstCell.frame.origin.y + 70), 300, 137)];
// Add border and round corners of image view to make style look a little like tableviewcells
[imageView.layer setBorderColor:[UIColor colorWithWhite:0 alpha:0.5].CGColor];
[imageView.layer setBorderWidth:2.0];
[imageView.layer setCornerRadius:5.0];
[imageView setClipsToBounds:YES];
//Set the image in the image view
UIImage *image = [UIImage imageNamed:#"defaultPicture.png"];
imageView.image = image;
//Set resizing of image view for when view is rotated
imageView.contentMode = UIViewContentModeRedraw;
imageView.autoresizingMask = UIViewContentModeScaleAspectFit;
//Add tap gesture for imageview to initiate taking picture.
imageView.userInteractionEnabled = YES;
UITapGestureRecognizer *imageViewTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(takePicture:)];
[imageView addGestureRecognizer:imageViewTap];
//Add image view to view
[self.view addSubview:imageView];
This has not been fully tested and i'm sure isn't a great implementation, but its a starting point for the effect i'm after. Please reply if you know of a better way.
Note: The above code is written for my app on the iPad but screenshots are from testing I did on iPhone
Related
Basically, I want to have an app with only one view that has an image on it. I want to be able to swipe left or right and have the first image go out of the view and the second image to come in. The images are the same and I want it to look like they are connected (like scrolling down a rope where the pattern just repeats, but it looks like a constant scroll). I need it to be able to change the image or restart after a series of swipes. I know that I need to turn pagination ON in the UIScrollView, but I am new to iOS and am having trouble.
Ultimately, I want to have the iPhone vibrate every so-and-so swipes (and restart the pattern).
I'm sure that there are a lot of ways to do this (i.e. a TableView) so feel free to just point me in the direction of some references if the answer is tedious to explain.
Thanks!
FOLLOW UP:
I found an Apple example that did very nearly what I wanted to do. I made a lot of adjustments to it, but I'm banging my head against a wall trying to get the images to cycle. Here is what I think is the offending code, but I'm not sure what the solution is, as the ScrollView is functional, it just doesn't reset the center to the current view. Any ideas?
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
// set the content size so it can be scrollable
[scrollView1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
I'd just use a UIScrollView. Set the contentWidth to be 3 times the width/height of the view (for 3 pages) and set the contentOffset to be the center 'page' (view.bounds.size.width or view.bounds.size.height depending on whether you're scrolling horizontally/vertically respectively) . You'll need to setup a delegate for the UIScrollView (probably the view controller) and implement - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView. This will be called when the scroll view has finished decelerating. Once it has finished decelerating, reset the contentOffset back to the center view. This should give the impression of an infinite scroll. You can also set a counter to increment in the scrollViewDidEndDecelerating method to increment the counter or initiate the vibration.
You shouldn't need to keep repositioning the images. Just set the images once in the scrollView:
//Horizontal arrangement
UIImage *image = [UIImage imageNamed:#"nameOfImage.png"];
UIImageView *imageView1 = [[UIImageView alloc] initWithImage:image];
UIImageView *imageView2 = [[UIImageView alloc] initWithImage:image];
UIImageView *imageView3 = [[UIImageView alloc] initWithImage:image];
NSArray *imageViews = [NSArray arrayWithObjects:imageView1, imageView2, imageView3];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
[self.view addSubview: scrollView]; //This code assumes it's in a UIViewController
CGRect cRect = scrollView.bounds;
UIImageView *cView;
for (int i = 0; i < imageViews.count; i++){
cView = [imageViews objectAtIndex:i];
cView.frame = cRect;
[scrollView addSubview:cView];
cRect.origin.x += cRect.size.width;
}
scrollView.contentSize = CGSizeMake(cRect.origin.x, scrollView.bounds.size.height);
scrollView.contentOffset = CGPointMake(scrollView.bounds.size.width, 0); //should be the center page in a 3 page setup
So the images are setup, you don't need to mess with them anymore. Just reset the contentOffset when the scroll views stops (note: you need to make sure you're the delegate of the scroll view or you'll not receive the message when the scroll view stops):
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
scrollView.contentOffset = CGPointMake(scrollView.bounds.size.width, 0);
}
Please forgive any typos. I wrote it out by hand.
Look on cocoacontrols.com for a custom photo album view. As for the vibration, this code snippet vibrates the phone (make sure you link to and #import <AudioToolbox/AudioToolbox.h>):
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
I have set imageView's frame in table using the following code.
cell.imageView.image = [UIImage imageWithContentsOfFile:[[users objectAtIndex:indexPath.row] valueForKey:#"ImagePath"]];
[cell.imageView setFrame:CGRectMake(5, 5, 10, 10)];
But image is displayed from the corner of the cell.
It does not changes the position or size.
what should I do ?
You will not be able to change the cells imageView frame. Your best option would be to create a custom cell.
You can change the frame of the cell by creating a subclass of UITableViewCell and overriding the layoutSubviews method.
In your subclass implementation of layoutSubviews, call super's implementation first and then modify the frame of imageView.
You can add your desired imageview as a subview to the cell
UIImageView *imageView = [[UIImageView alloc] init];
imageView.image = [UIImage imageWithContentsOfFile:[[users objectAtIndex:indexPath.row] valueForKey:#"ImagePath"]];
[imageView setFrame:CGRectMake(5, 5, 10, 10)];
[cell addSubview:imageView];
You can create custom table view cells and position the elements where you want them to be.
Its also helpful as you will have control on how similar you want your UI to be be to the requirements.
You can do it in interface builder or in code. Also there are loads of examples as this is most common approach in iphone app development (Having a custom table view cell) and you can use the delegates to populate the table view and it works like a charm.
I'd like to apply a margin to the UIImageView on the left of a plain old UITableViewCell (grouped style).
The only way I've found to do this (via here) is to resize the UIImage itself before attaching it to the UIImageView. If the image is smaller then the cell, it will be centred; leaving the desired margin as a side-effect.
Well, that works, but now my image is blurry because the 100 unit row height is not 100 pixels on an iPhone4, its 200. So I end up with a UIImage scaled to 90x90 pixels that produces a 90x90 unit (180x180 pixel) UIImageView image. Enter ugly blurriness.
So my question is: how do I achieve a margin around the imageView without over-downsampling my image?
(ideally without downsampling at all - I need to keep the original for later anyway).
I feel like I'm missing something obvious; I really don't want to implement a custom cell class just for this.
Thanks guys, I've come up with a 'solution' that doesn't require subclassing.
What I do is still downsample the image, but to the 2x size (180x180 from the example in the question).
Then, when I come to create the final UIImage from the processed CGImage I use:
UIImage: +(UIImage *)imageWithCGImage:(CGImageRef)imageRef scale:(CGFloat)scale orientation:(UIImageOrientation)orientation
and set scale: to 2. Now everything works. But I'm still creating duplicate images just to keep UIKit happy.
Implement this method in your UITableViewCell subclass
-(void) layoutSubviews
{
[super layoutSubviews];
self.imageView.frame = CGRectInset(self.imageView.frame, 5, 5);
}
Note: I haven't tested any of this, so it's possible that UITableViewCell will override some of these settings to lay its subviews out according to its own internal logic.
Have you tried just adjusting the image view's frame? Try this:
UITableViewCell * tableViewCell = [[[UITableViewCell alloc] init] autorelease];
tableViewCell.imageView.image = [UIImage imageNamed:#"table-view-image"];
CGRect imageViewFrame = tableViewCell.imageView.frame;
imageViewFrame.origin.x += 10.0f;
tableViewCell.imageView.frame = imageViewFrame;
That will just pad the image view 10 points more than its normal x coordinate. If you want to pad both sides, you can also set the contentMode property on the image view to UIViewContentModeCenter and adjust its width:
UITableViewCell * tableViewCell = [[[UITableViewCell alloc] init] autorelease];
tableViewCell.imageView.image = [UIImage imageNamed:#"table-view-image"];
tableViewCell.imageView.contentMode = UIViewContentModeCenter;
CGRect imageViewFrame = tableViewCell.imageView.frame;
imageViewFrame.size.width += 20.0f;
tableViewCell.imageView.frame = imageViewFrame;
That will make the image view 20 points wider, but because the content mode is set to center, the image will be drawn without stretching. If the dimensions of your image are right, this will effectively pad the image by 10 points on the left and right. However, you need to be aware that if you do this, the UIImage you provide must already be the exact dimensions to fit in the image view. contentMode's default setting is UIViewContentModeScaleToFill, so it will automatically scale images to fill the image view's frame. Setting it to UIViewContentModeCenter will no longer do this, but it will center the actual image.
In my case I used my own subclass inherited from UITableViewCell.
It's very clean and easier to use.
Also, I could use different sizes of image to be well resized for this cell.
The point is to use additional property that will replace regular imageView
1: In the subclass, I added a property mainImageView which can be used instead of imageView.
#property (nonatomic, retain) UIImageView *mainImageView;
2: Then in - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier.
I allocated and initialized mainImageView.
You can set any frame(rect) for mainImageView.
Add it as a subview to the contentView.
I used insetImageView to align it to the vertical middle of `contentView'.
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code.
mainImageView = [[UIImageView alloc] initWithFrame:frameCellMainImageView];
[self.contentView addSubview:mainImageView];
insetImageView = (sizeRowHeightTwoLinedDetail - frameCellMainImageView.size.height) / 2.0;
}
return self;
}
3: Override - (void)layoutSubviews to make sure other properties like textLabel, detailTextLabel set their frames to be well-situated with added property mainImageView
- (void)layoutSubviews {
[super layoutSubviews];
CGRect frameImageView = frameCellMainImageView;
frameImageView.origin.x = insetImageView;
frameImageView.origin.y = insetImageView;
[self.mainImageView setFrame:frameImageView];
// Use changed frame
frameImageView = self.mainImageView.frame;
CGFloat newLeftInset = frameImageView.size.width + insetImageView;
CGRect frameTextLabel = self.textLabel.frame;
CGRect frameDetailLabel = self.detailTextLabel.frame;
frameTextLabel.origin.x += newLeftInset;
frameDetailLabel.origin.x += newLeftInset;
CGFloat newTextWidth = 320.0;
newTextWidth -= newLeftInset;
newTextWidth -= insetImageView;
newTextWidth -= insetImageView;
frameTextLabel.size.width = newTextWidth;
frameDetailLabel.size.width = newTextWidth;
[self.textLabel setFrame:frameTextLabel];
[self.detailTextLabel setFrame:frameDetailLabel];
}
4: When using this cell in UITableDataSourceDelegate methods, use cell.mainImageView to receive messages, instead of regular cell.imageView
I have some code that creates a table cell with a slider. It's pretty straightforward and it sizes well on the iPhone. I've anonymized it a bit here:
UITableViewCell* cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Foo"] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
CGRect contentViewFrame = cell.contentView.frame;
CGRect sliderFrame = CGRectMake(10, 0, 280, contentViewFrame.size.height);
UISlider* slider = [[UISlider alloc] initWithFrame:sliderFrame];
UIImage* minimumImage = [UIImage imageNamed:#"min.png"];
UIImage* maximumImage = [UIImage imageNamed:#"max.png"];
slider.minimumValueImage = minimumImage;
slider.maximumValueImage = maximumImage;
slider.value = 0.5f;
[slider addTarget:self action:#selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
[cell.contentView addSubview:slider];
[slider release];
Of course, this is incorrectly sized for the iPad. So my first thought was to set the autoresizingMask property to UIViewAutoresizingFlexibleWidth. Problem solved, right? Nope. Now on the iPhone, the width of the slider-plus-images content is less than 280 and so it doesn't go right to the end -- it ends up about 20 pixels short.
On the iPad, the same thing -- the width of the UISlider automatically resizes to about 20 pixels short of the end of the cell.
Perhaps the auto resize flag is paying attention to the non-existent accessoryView of the cell? I tried setting it to nil explicitly, but I think it's nil by default, so nothing changed.
I'd like this cell's content to resize automatically to be the "full" width of the cell, regardless of device and orientation. Is there an easy way to do this?
It works exactly how you described. I am inclined to think it's iOS bug. On iPAD when you create new UITableViewCell its width set for 320. hardcoded(!) both view and contentView. It does not resize properly if set to UIViewAutoresizingFlexibleWidth. I had it set to view.frame.size.width/2 with funny results: on iPhone it's 160, on iPad it's 608!!!
I ended up manually resizing my cells and their content.
Bit late but i found the solution of the same question today, but you need to create a custom UITableViewCell.
Then you can overwrite the function
- (void) layoutSubviews
{
[dateLabel setFrame:CGRectMake(10.f, 16.f, 80.f, 12.f)];
[textLabel setFrame:CGRectMake(106.f, 16.f, contentView.frame.size.width-105.f + 1.f, 12.f)];
}
In that function the self.frame.size.width is the actual one.
And it works with rotation of the device, too.
You should be able to tell the resizing system to "stick" the object a fixed distance from the right edge (where it's not resizing far enough). If you experiment with IB you can create a view that resizes in width and is fixed to the right side.
Do you have UIViewAutoresizingFlexibleRightMargin set as well?
Set your cell's contentMode to UIViewContentModeRedraw.
I am pretty new to iphone programming. I just started about a month ago and have only been tinkering with small tutorial type applications but anyways, here is my question.
I currently have a UIScrollView thats scrollable and zoomable, that loads a UIImageView subview, and i want to add in some controls(UIButtons) over the image view but when i zoom in and out the whole group(the buttons and the image) zoom togeather.
If I add the UIButtons to my UIScrollView and zoom, the image zooms and the buttons stay in origional place
If I add the UIButtons to my UIImageView they zoom correctly but arent buttons anymore. IE they lose their interactivity.
Later ill add lots of buttons into an array and add them.
I would appreciate any help i can get
This is part of my mainViewController.m:
- (void)viewDidLoad
{
[scrollView2 setBackgroundColor:[UIColor blackColor]];
[scrollView2 setCanCancelContentTouches:NO];
scrollView2.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView2.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scroll2ImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"bigNH.jpg"]];
[scrollView2 addSubview:scroll2ImageView];
[scrollView2 setContentSize:CGSizeMake(scroll2ImageView.frame.size.width, scroll2ImageView.frame.size.height)];
scrollView2.minimumZoomScale = .5;
scrollView2.maximumZoomScale = 3;
scrollView2.delegate = self;
[scrollView2 setScrollEnabled:YES];
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect newSize = CGRectMake(658, 435, 50, 50); // position in the parent view and set the size of the button
myButton.frame = newSize;
[myButton setImage:[UIImage imageNamed:#"redStop.png"] forState:UIControlStateNormal];
// add targets and actions
[myButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
// add to a view
[scroll2ImageView addSubview:myButton];
[redLineArray addObject:myButton];
[scroll2ImageView release];
}
This might not help and it is not what it appears that you want to do.
However, when I want buttons associated with a scrollview, I add a parent view, add the buttons to that view and also add the scrollview to that view. The button(s) and the scrollview would be siblings. This allows the user to scroll around the contents of the scrollview, while insuring that the buttons are always in view.
-isdi-
By default, UIImageView has userInteraction disabled. Have you changed this?
Also, I would be really uneasy adding subviews to an UIImageView, it's really meant to hold one image. It would be better to create a normal UIView and add the UIButtons and UIImageView to that. It's very easy to control the ordering so that the buttons appears on top of the image.
P.S. Just to make your life easier, instead of :
[scrollView2 setContentSize:CGSizeMake(scroll2ImageView.frame.size.width, scroll2ImageView.frame.size.height)];
You can use :
[scrollView2 setContentSize:scroll2ImageView.frame.size];
Make a single view to contain all your zoomable content (everything it would appear), and call it say contentView. Now place everything you want in that contentView, the imageView and all your buttons etc.
In your UIScrollView delegate place this: (Be sure to set the scrollView's delegate if you haven't already)
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.contentView;
}
Only one view is allowed to zoom, but that one view can however contain other views that will scale because they're child views.
Also be sure to set the scrollView's contentSize value to the exact size of your zoomable contentView.