I want to draw an rectangle and can change the rectangle's position and size realtime.
I have tried following two methods, but the view don't show the rectangle.
do you have any advice or example?
appreciate your help.
use view frame (it only show the new rectangle when restart the app)
UIView * drawView = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 10, 10)];
[self.view addSubview:drawView];
drawView.layer.borderColor = [[UIColor orangeColor] CGColor];
drawView.layer.borderWidth = 2;
drawView.frame = CGRectMake(r.x, r.y, r.width, r.height);
draw in the drawRect
fav = [[FaceAugmentingView alloc] initWithFrame:[imageView frame]];
fav.backgroundColor = [UIColor clearColor];
[self.view addSubview: fav ];
fav.face = CGRectMake(r.x, r.y, r.width, r.height);
[fav setNeedsDisplay];
I suggest you add a method that reloads the faces based whenever you need to alter it. Declare and array that will help us keep track of all the views we've added.
#interface FacesViewController: UIViewController
[..]
#property (nonatomic, retain) NSMutableArray * faceViews;
- (void)reloadFaces;
[..]
#end
And then implement reloadFaces something like this -
- (void)reloadFaces {
/* remove all current views we've added */
for ( UIView * aView in self.faceViews ) {
[aView removeFromSuperview];
}
[self.faceViews removeAllObjects];
/* Add news ones */
int numberOfFaces = [self numberOfFacesInImage];
for ( int i = 0; i < numberOfFaces; i++ ) {
CGRect faceFrame = [self frameForFaceAtIndex:i];
UIView * drawView = [[[UIView alloc] initWithFrame:faceFrame] autorelease];
drawView.layer.borderColor = [[UIColor orangeColor] CGColor];
drawView.layer.borderWidth = 2;
drawView.frame = CGRectMake(r.x, r.y, r.width, r.height);
[self.view addSubview:drawView];
[faceViews addObject:drawView];
}
}
I would expect reloadFaces to be called when there is a change of some kind. numberOfFacesInImage and frameForFaceAtIndex: are methods that you will have to implement based on how you get the data. You can also replace them to suit your data model. Don't forget to initialize faceViews.
Related
I followed the tutorial about how to create a scrollView Page Control: http://www.iosdevnotes.com/2011/03/uiscrollview-paging/
This tutorial is really good and I implement well the code. Here my question:
I want to put a space between the my PageViews, but when it change the page it show the space between the views in the next page. The scroll must stop after the space when I change the page.
I changed the tutorial code here:
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *colors = [NSArray arrayWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor blueColor], nil];
#define space 20
for (int i = 0; i < colors.count; i++) {
CGRect frame;
frame.origin.x = (self.scrollView.frame.size.width + space) * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.
UIView *subview = [[UIView alloc] initWithFrame:frame];
subview.backgroundColor = [colors objectAtIndex:i];
[self.scrollView addSubview:subview];
[subview release];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * colors.count+ space*(colors.count-1), self.scrollView.frame.size.height);
}
It sounds like you want a “gutter” between the pages, so that each page fills the scroll view and the gutter is only visible while the user is dragging the view. The built-in Photos app does this, for example.
Make your scroll view wider by space points. For example, if you want the scroll view to appear to be as wide as the screen (320 points), with a 20 point margin between items, then make the scroll view 340 points wide, with the extra 20 points hanging off the right edge of the screen.
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *colors = [NSArray arrayWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor blueColor], nil];
#define kGutterWidth 20
UIScrollView *scrollView = self.scrollView;
CGRect scrollViewFrame = scrollView.frame;
scrollViewFrame.size.width += kGutterWidth;
scrollView.frame = scrollViewFrame;
CGSize scrollViewSize = scrollView.bounds.size;
for (int i = 0; i < colors.count; i++) {
CGRect frame = CGRectMake(scrollViewSize.width * i, 0,
scrollViewSize.width - kGutterWidth, scrollViewSize.height);
UIView *subview = [[UIView alloc] initWithFrame:frame];
subview.backgroundColor = [colors objectAtIndex:i];
[scrollView addSubview:subview];
[subview release];
}
scrollView.contentSize = CGSizeMake(
colors.count * scrollViewSize.width,
scrollViewSize.height);
}
I've been down this road before, and I would advise laying out the scroll view as the tutorial code recommends, with no space between the subviews.
Instead, give each subview another subview whose frame is inset from it's parent...
CGRect scrollViewFrame = self.scrollView.frame;
for (int i=0; i<colors.count; i++) {
CGRect frame = CGRectMake(scrollViewFrame.size.width * i, 0, scrollViewFrame.size.width, scrollViewFrame.size.height);
// this will be our framing view, full size with no gaps
UIView *subview = [[UIView alloc] initWithFrame:frame];
subview.backgroundColor = [UIColor whiteColor];
// here's the trick - use CGRectInset on the framing view's bounds
UIView *colorView = [[UIView alloc] initWithFrame:CGRectInset(subview.bounds, 10, 10)];
colorView.backgroundColor = [colors objectAtIndex:i];
[subview addSubview:colorView];
[self.scrollView addSubview:subview];
// aren't you using ARC? your tutorial is probably older than ARC
// would strongly suggest converting to ARC
[subview release];
[colorView release];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * colors.count, self.scrollView.frame.size.height);
The benefit of this approach is that the math for the top level subview layout remains a simple multiple of the width. The only place you'll refer to that inset constant is on the CGRectInset where it belongs.
In my app i am creating view controller with mixed of UILabel and UITextview which want to be scrollable because the text are dynamic and also exceeds vertical screen size.
I am currently having Scrollview which has subviews as below. Views are created in Xcode 4.3 Storyboard.
UILabel1(Say Heading)
UITextView1(Dynamic text which can be any size)
UILabel2(Second Heading)
UITextView2(Dynamic text which can be any size)
and so on.
The problem is
When the UITextView1 has more content then it overlaps with UILabel2 which i don't want.
I would like to have UILabel1 on top of scrollView and UITextView1 below the UILabel1. UILabel2 below UITextView1 and so on.
What i have to do to achieve this?
EDIT
In Storyboard
![enter image description here][1]
In Simulator
![enter image description here][2]
Thanks for your help guys. Much appreciated.
Code
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[scrollView setScrollEnabled:YES];
[self.view addSubview:cockTailNameLabel];
[self.view insertSubview:txtIngredients belowSubview:cockTailNameLabel];
[self.view insertSubview:scrollView belowSubview:cockTailNameLabel];
//[scrollView]
[self.cockTailNameLabel setText:self.passcockTailName];
[_txtUse setText:self.passUse];
[_txtUse setEditable:NO];
[_txtUse setUserInteractionEnabled:NO];
CGRect useFrame = _txtUse.frame;
useFrame.size.height = _txtUse.contentSize.height;
_txtUse.frame = useFrame;
[txtIngredients setText:self.passIngredients];
[txtIngredients setEditable:NO];
[txtIngredients setUserInteractionEnabled:NO];
CGRect ingredientFrame = txtIngredients.frame;
ingredientFrame.size.height = txtIngredients.contentSize.height;
txtIngredients.frame = ingredientFrame;
[txtRecipe setText:self.passReceipe];
[txtRecipe setEditable:NO];
[txtRecipe setUserInteractionEnabled:NO];
CGRect recipeFrame = txtIngredients.frame;
recipeFrame.size.height = txtRecipe.contentSize.height;
txtRecipe.frame = recipeFrame;
[scrollView insertSubview:_txtUse belowSubview:cockTailNameLabel];
[scrollView insertSubview:titleIngredients belowSubview:_txtUse];
[scrollView insertSubview:txtIngredients belowSubview:titleIngredients];
[scrollView insertSubview:btnReceipe belowSubview:txtIngredients];
[scrollView insertSubview:btnHome belowSubview:txtIngredients];
[scrollView insertSubview:txtRecipe belowSubview:btnHome];
[scrollView insertSubview:btnfacebookShare belowSubview:txtRecipe];
[scrollView insertSubview:btnTwitterShare belowSubview:txtRecipe];
/*[scrollView addSubview:_txtUse];
[scrollView addSubview:titleIngredients];
[scrollView addSubview:txtIngredients];
[scrollView addSubview:btnReceipe];
[scrollView addSubview:btnHome];
[scrollView addSubview:txtRecipe];
[scrollView addSubview:btnfacebookShare];
[scrollView addSubview:btnTwitterShare];*/
[scrollView setContentSize:CGSizeMake(320, 1000)];
NSLog(#"RecipeName :%# ",passcockTailName);
}
In Storyboard or IB you can rearrange them freely.
In code you do - (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview.
In code (in viewDidLoad):
UIScrollView *scroll =[[UIScrollView alloc] initWithFrame:CGrectMake(0,0 320, 480)];
[self.view addSubview:scroll];
// code to init your UI object
UILabel *uilabel1 = [[UIlabel alloc] initWithFrame:CGrectMake(10,10, 100, 40)]; // example
uilabel1.font = [UIFont systemFontOfSize:10];
uilabel1.text = #"UILabel1";
uilabel1.backgroundColor = [UIColor clearColor];
//
//
UILabel *uilabel2 = [[UIlabel alloc] initWithFrame:CGrectMake(10, 10 + 10 + uilabel1.frame.origin.y, 100, 40)]; // example
uilabel2.font = [UIFont systemFontOfSize:10];
uilabel2.text = #"UILabel2";
uilabel2.backgroundColor = [UIColor clearColor];
//
//
[scroll addSubview:uilabel1];
[uilabel1 releale];
[scroll addSubview:uilabel2];
[uilabel2 releale];
//
//
// in end
float offset = 10.0 * 2; // offset between uiobjects, N - number of objects
scroll.contentSize = CGSizeMake (0, 0, uilabel1.frame.size.height + uilabel2.frame.size.height + offset, 320);
Note that you may set frame (and other properties) of yours uiobjects and adds it in order to descend.
You can tell next view to start from the end of the first view like so:
startYOfNextView = firstView.frame.origin.y position + firstView.frame.size.height;
Do the same for the rest of the other view. If your view has variable text length, you may need to precaculate the height of the string based on a specific font e.g.:
CGSize maxSize = CGSizeMake(widthOfView, 9999999);
CGSize expectedSize = CGSizeMake(stringVar sizeWithFont:[UIFont fontWithName:#"Arial"] withMaxSize:maxSize lineBreakMode:UILineBreakModeWordWrap);
then tell your dynamic view to use the height of expectedSize variable like so:
myDynamicView = [[UILabel alloc] initWithFrame:CGRectMake(..., expectedSize.height)];
Your issue is labels are coming on top of the textview (Overlapped), right?
In This case, you are modifying the height of the textview dynamically. If its just for display purpose you can set the text to a UILabel with numberOfLines = 0 instead of UITextview; As its added to scrollview adding a label will be fine.
Also you need to modify the origin.y of the remaining views so that it will be properly aligned. ie, secondView.origin.y = firstView.origin.y + firstView.size.height + offset. Likewise modify the origin of the remaining views wrt the just above view. So that its origin will lie outside the previous view frame.
In my case I had to project it over the parent view, so remember there is also something,
- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview
I think adding a transparent UI button is the fastest solution. You could add it once and then show / hide whenever you need to disable all views below the current one (assuming the "current" view, say a popup, was added last to your superview).
Declare an instance variable UIButton* _parentDisablingOverlay; in your popup view, then add this in its init or layoutSubviews method:
_parentDisablingOverlay = [[UIButton alloc] initWithFrame:CGRectMake(0,0, self.superview.frame.size.width, self.superview.frame.size.height)];
[self.superview insertSubview:_parentDisablingOverlay belowSubview:self];
_parentDisablingOverlay.hidden = true;
Later on, when you want to show the popup and disable everything below:
- (void) open {
self.hidden = false;
_parentDisablingOverlay.hidden = false;
}
Similarly to close and re-enable everything:
- (void) close {
self.hidden = true;
_parentDisablingOverlay.hidden = true;
}
I am trying to Load 5 or 6 remotes images to a scrollview and swipe horizontal. I can get the URLs form my webserver (JSON output) , I'm trying to do this using AFnetworking for performances issues .
so far I can get the URL and load one picture to a UIImageview like this (Using Storyboard )
Jsonobject *items = [posterNSMarray objectAtIndex:0]; //load one url only
NSlog (#"Object url %#", items.pUrl); // picture URL
[self.imageview setImageWithURl :[NSURL URLWithString:items.pUrl] placeholderImage :[UIImage imageNamed:#"placeholder"]];
[EDITED QUESTION]
my question is how do I get all the images and save it to a NSMutableArray
Thanks for your help .
[EDIT]
Based upon your comments below, I might actually choose then a different methodology
Bring in All of your images. At this point you can use either UIImageView or UIButton actually to obtain the tap (from the scrollview) you wish. Assign the UIImages to your choice of UIButton or UIImageView, and the place them on your scrollview as you wish. You will have to dynamically create the actions for each Button or ImageView. Your action creation should then bring up another View to be place atop you scrollview, or another viewcontroller that you animate to, etc... In a View Controller you will have your UIImageView as full screen. At this point you can implement your own UIGestureRecognizers to implement the double taps, etc...
I would use a UIListView. Here is a great link to custom UIListView implementation.
http://cocoawithlove.com/2009/04/easy-custom-uitableview-drawing.html
I would load your images into an NSMutableArray, to be used by the drawing routine of the custom UITableView.
As for swiping, you can capture the swipe events, then you can do with the list items as you please (i.e. delete, edit, etc... from your image array).
Another link:
http://www.icodeblog.com/2009/05/24/custom-uitableviewcell-using-interface-builder/
From your question and comments it seems like you want to load a UIScrollView with multiple images and then swipe through each one. It also sounds like you want to be able to tap one and have it launch a blown up image for the user to view.
I wrote some of these functions for an old project (they are a little rough) but you may be able to use them as they are how I accomplished what I think you were asking.
-(void)setupPictures
{
imageSectionSlider = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, 320, IMAGE_HEIGHT)];
imageSectionSlider.showsVerticalScrollIndicator = NO;
imageSectionSlider.showsHorizontalScrollIndicator = NO;
imageSectionSlider.pagingEnabled = YES;
imageSectionSlider.bounces = NO;
UIView* tilesHolder = [[UIView alloc]initWithFrame:CGRectMake(0, 0, (([[thisStory imageList]count] * (self.frame.size.width))), IMAGE_HEIGHT)];
tilesHolder.userInteractionEnabled = YES;
for (int count = 0; count < [[thisStory imageList]count]; count++)
{
[tilesHolder addSubview:[self createImageTile:[[thisStory imageList]objectAtIndex:count] Count:count Rect:CGRectMake( 320*count , 0, 320, IMAGE_HEIGHT)]];
}
[imageSectionSlider setContentSize:CGSizeMake( tilesHolder.frame.size.width , tilesHolder.frame.size.height)];
[imageSectionSlider addSubview:tilesHolder];
[tilesHolder release];
}
-(UIView*)createImageTile:(ImageItem*)input Count:(int)count Rect:(CGRect)rect
{
UIView* imageTile = [[UIView alloc]initWithFrame:rect];
[imageTile setTag:count];
UIImageView* image = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, imageTile.frame.size.width, imageTile.frame.size.height - 45)];
[image setImage:[input imageData]];
image.contentMode = UIViewContentModeScaleAspectFill;
image.clipsToBounds = YES;
image.userInteractionEnabled = YES;
image.tag = count;
UIGestureRecognizer* featureImageGesRec = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(countTaps:)];
[image addGestureRecognizer:featureImageGesRec];
[featureImageGesRec release];
[imageTile addSubview:image];
[image release];
return [imageTile autorelease];
}
- (void)countTaps:(NSObject*)sender {
tapCount++;
if (tapCount == 1) {
//do something with single tap
}
else if (tapCount == 2)
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[self doubleTap:sender];
}
}
-(void)doubleTap:(NSObject*)sender
{
UITapGestureRecognizer* item = (UITapGestureRecognizer*)sender;
tapCount = 0;
//FullSizeImage
ImageItem* selectedItem = [[thisStory imageList]objectAtIndex:item.view.tag];
ExpandedView* pictureView = [[ExpandedView alloc]initWithImage:[selectedItem imageData]];
[thisParent.navigationController pushViewController:pictureView animated:YES];
[pictureView release];
}
Just pass your async loaded image here in this line...
[tilesHolder addSubview:[self createImageTile:/*Image*/ Count:count Rect:CGRectMake( 320*count , 0, 320, IMAGE_HEIGHT)]];
if you use AFNetworking Conect, you use Image Request concept :-
try this code:-
- (void)setupPage
{
scrollPage = 0 ;
scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0.0f,0, 320,367)];
[scrollView setBackgroundColor:[UIColor clearColor]];
[scrollView setDelegate:self];
[self.view addSubview:scrollView];
NSUInteger nimages = 0;
CGFloat cx = 0;
CGFloat cy = 0;
for (; nimages < [stealArr count]; nimages++)
{
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f,320.0f,367)];
CGRect rect = imageView.frame;
rect.size.height = 331;
rect.size.width = 320.0f;
rect.origin.y = 0.0f;
rect.origin.x = 0.0f+cx;
imageView.frame = rect;
[imageView setBackgroundColor:[UIColor clearColor]];
imageView.contentMode = UIViewContentModeScaleToFill;
[scrollView addSubview:imageView];
[imageView setImageWithURL:[NSURL URLWithString:#"http://i.imgur.com/r4uwx.jpg"] placeholderImage:[UIImage imageNamed:#"placeholderImage"]];
cx += scrollView.frame.size.width;
cy += scrollView.frame.size.height;
}
pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 331.0f, 320, 36)] ;
[pageControl setCurrentPage:0] ;
[pageControl addTarget: self action: #selector(pageControlClicked:) forControlEvents: UIControlEventValueChanged] ;
[pageControl setDefersCurrentPageDisplay: YES];
[pageControl setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:pageControl];
pageControl.numberOfPages = [stealArr count];
[scrollView setContentSize:CGSizeMake(cx,[scrollView bounds].size.height)];
[scrollView setPagingEnabled:TRUE];
}
when Your are scroll the page
- (void)scrollViewDidScroll:(UIScrollView *)sender {
// We don't want a "feedback loop" between the UIPageControl and the scroll delegate in
// which a scroll event generated from the user hitting the page control triggers updates from
// the delegate method. We use a boolean to disable the delegate logic when the page control is used.
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = scrollView.frame.size.width;
scrollPage = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = scrollPage;
be to unload the views+controllers which are no longer visible
}
for Paging
- (void)pageControlClicked:(id)sender
{
UIPageControl *thePageControl = (UIPageControl *)sender ;
// we need to scroll to the new index
[scrollView setContentOffset: CGPointMake(scrollView.bounds.size.width * thePageControl.currentPage, scrollView.contentOffset.y) animated: YES] ;
}
In the iPhone calendar app if you have 2 tiles overlaying ontop of each other the text from the bottom tile gets cut off and cannot be seen through the top transparent tile. How would I be able to keep the tiles transparent but not have the text from the bottom tiles show through to the top tiles?
Here is my code
APCalendarDayTile *tile = (APCalendarDayTile *)view;
CGFloat startPos = [APCalendarCurrentDayView yAxisForTime:[APCalendarCurrentDayView minutesToTime:tile.appointment.startDate]];
CGFloat endPos = [APCalendarCurrentDayView yAxisForTime:[APCalendarCurrentDayView minutesToTime:tile.appointment.endDate]];
tile.frame = CGRectMake(kLeftSideBuffer, startPos, (self.bounds.size.width - kLeftSideBuffer - kRightSideBuffer) , endPos - startPos);
tile.backgroundColor = [UIColor colorWithHexString:tile.appointment.appointmentColor]; <-- This also sets the alpha that makes it transparent.
tile.layer.borderColor = [UIColor colorWithHexString:tile.appointment.appointmentColor alpha:1.0].CGColor;
tile.layer.borderWidth = 1.0f;
Tile code
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
CALayer *layer = [self layer];
[layer setMasksToBounds:YES];
[layer setCornerRadius:kCornerRadius];
}
return self;
}
- (id)init
{
if (self = [super init]) {
self.clipsToBounds = YES;
self.userInteractionEnabled = YES;
self.multipleTouchEnabled = NO;
tileTitle = [[UILabel alloc] init];
tileTitle.textColor = [UIColor blackColor];
tileTitle.backgroundColor = [UIColor clearColor];
tileTitle.font = [UIFont boldSystemFontOfSize:13.0f];
[tileTitle setAutoresizesSubviews:YES];
[tileTitle setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
tileDescription = [[UILabel alloc] init];
tileDescription.textColor = [UIColor blackColor];
tileDescription.backgroundColor = [UIColor clearColor];
tileDescription.font = [UIFont systemFontOfSize:11.0f];
tileDescription.lineBreakMode = UILineBreakModeTailTruncation;
[tileDescription setAutoresizesSubviews:YES];
[tileDescription setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[self setAutoresizesSubviews:YES];
[self setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[self addSubview:tileTitle];
[self addSubview:tileDescription];
}
return self;
}
- (void)layoutSubviews
{
CGRect myBounds = self.bounds;
CGSize stringSize = [tileTitle.text sizeWithFont:tileTitle.font];
if (myBounds.size.height <= 22.0) {
tileTitle.frame = CGRectMake(3, 0, myBounds.size.width, stringSize.height);
tileDescription.frame = CGRectMake(stringSize.width + 6, -1, myBounds.size.width, 14);
} else {
tileTitle.frame = CGRectMake(3, 0, myBounds.size.width, stringSize.height);
tileDescription.frame = CGRectMake(5, tileTitle.frame.size.height, myBounds.size.width, 14);
}
}
I would like the text in this photo to not show in the front tiles like the second photo.
#user1272965 is right insofar as each tile needs to know what tiles are above it, then you can get the text effect you're looking for by making the tile views a custom subclass and implementing their drawing manually:
Each tile will need access to tiles that are above it (or their frames at least):
NSInteger tileCount = [tilesAboveMine count];
CGRect framesAboveMine[tileCount];
for (int i=0; i<tileCount; i++) {
framesAboveMine[i] = [tilesAboveMine objectAtIndex:i].frame;
}
In drawRect of your tile view, draw the tile, and then draw the text clipped by the views above it:
// draw aspects of the tile not to be clipped, like the background image.
// the setup for clipping:
CGContextClipToRects(context, framesAboveMine, tileCount);
then draw the text, which will be clipped by the frames above
[myCalendarString drawAtPoint:CGPointMake(10,10)];
What about adding a UIView in between the two boxes? This middle UIView would cover up the letters (and have the same background color as the rear event), which solves your problem: no text coming through, but you'll see the color behind the other label!
You might be able to create the frame for this UIView using the frame attribute of the UILabel as well as the frame attribute of the frontmost calendar appointment.
I think the native calendar app squeezes tiles that occur at the very same start time as you do, but it also squeezes tiles whose times overlap, i.e. if the start time of the later tile is between the start and end time of the earlier tile.
But if you need your UI to draw these tiles overlapping, then there's no way around it: the obscured tile needs to know that it's underneath (starting after and overlapping), and it needs to either hide its labels, or reduce their alpha level.
I want to build a view to be look like the bookshelf in NewsStand application ...
is here any ready made open source project that does this job or similar view ?
EDIT: newsstand :
AQGridView with a pattern UIImage of a single book shelf. The example is a springboard, so a modification of the source cell is necessary. If you'll allow me a couple minutes to find my computer, I'll gladly post source code that should help.
EDIT: Download the AQGridView source from Github and unzip the files into the directory of your choice.
Navigate to the project called ‘Image Demo’ and the other project called ‘Springboard.’ You want the springboard project. Copy EVERYTHING except his the pre-existing items in your project (so exclude the main.m and the prefix).
The important set of files is the SpringboardIconCell Class. From here, you modify the cell. This is how I layed it out:
//.h
#import <UIKit/UIKit.h>
#import "AQGridViewCell.h"
#import <Foundation/Foundation.h>
#interface SpringBoardIconCell : AQGridViewCell.
{
UIImageView * _iconView;
UILabel * _title;
UILabel * _titleTwo;
}
#property (nonatomic, retain) UIImage * icon;
#property (nonatomic, copy) NSString * title;
#property (nonatomic, retain) NSString * titleTwo;
//.m
#import "SpringBoardIconCell.h"
#import <QuartzCore/QuartzCore.h>
#implementation SpringBoardIconCell
- (id) initWithFrame: (CGRect) frame reuseIdentifier:(NSString *) reuseIdentifier
{
self = [super initWithFrame: frame reuseIdentifier: reuseIdentifier];
if ( self == nil )
return ( nil );
UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(0.0, 0.0, 155.0, 250.0)
cornerRadius: 18.0];
_iconView = [[UIImageView alloc] initWithFrame: CGRectMake(0.0, 0.0, 155.0, 250.0)];
_iconView.backgroundColor = [UIColor clearColor];
_iconView.opaque = NO;
_iconView.layer.shadowPath = path.CGPath;
_iconView.layer.shadowRadius = 0.0;
_iconView.layer.shadowOpacity = 0.0;
_iconView.layer.shadowOffset = CGSizeMake( 20.0, 20.0 );
_title = [[UILabel alloc] initWithFrame: CGRectZero];
_title.highlightedTextColor = [UIColor blackColor];
_title.font = [UIFont boldSystemFontOfSize: 12.0];
_title.adjustsFontSizeToFitWidth = YES;
_title.minimumFontSize = 12.0;
_title.backgroundColor = [UIColor clearColor];
_title.textColor = [UIColor whiteColor];
_title.textAlignment = UITextAlignmentCenter;
_title.numberOfLines = 1;
_titleTwo = [[UILabel alloc] initWithFrame: CGRectZero];
_titleTwo.highlightedTextColor = [UIColor blackColor];
_titleTwo.font = [UIFont fontWithName:#"AmericanTypewriter" size:20];
_titleTwo.adjustsFontSizeToFitWidth = YES;
_titleTwo.minimumFontSize = 18.0;
_titleTwo.backgroundColor = [UIColor clearColor];
_titleTwo.textColor = [UIColor blackColor];
_titleTwo.textAlignment = UITextAlignmentRight;
_titleTwo.numberOfLines = 4;
[self.contentView addSubview: _iconView];
[_iconView addSubview: _title];
[self.contentView addSubview:_titleTwo];
[self.contentView bringSubviewToFront:_titleTwo];
self.contentView.backgroundColor = [UIColor clearColor];
self.backgroundColor = [UIColor clearColor];
self.contentView.opaque = NO;
self.opaque = NO;
self.selectionStyle = AQGridViewCellSelectionStyleNone;
return ( self );
}
- (void) dealloc
{
[_title release];
[_iconView release];
[super dealloc];
}
- (UIImage *) icon
{
return ( _iconView.image );
}
- (void) setIcon: (UIImage *) anIcon
{
_iconView.image = anIcon;
[self setNeedsLayout];
}
- (CALayer *) glowSelectionLayer
{
return ( _iconView.layer );
}
- (NSString *) title
{
return ( _title.text );
}
- (NSString*)titleTwo {
return (_titleTwo.text);
}
- (void) setTitle: (NSString *) title
{
_title.text = title;
[self setNeedsLayout];
}
-(void)setTitleTwo:(NSString *)titleTwo {
_titleTwo.text = titleTwo;
[self setNeedsLayout];
}
- (void) layoutSubviews
{
[super layoutSubviews];
[_titleTwo setFrame:CGRectMake(self.contentView.frame.origin.x + 45, 10, 135, 100.0f)];
CGSize imageSize = _iconView.image.size;
CGRect bounds = CGRectInset( self.contentView.bounds, 10.0, 10.0 );
[_title sizeToFit];
CGRect frame = _title.frame;
frame.size.width = 155.0;
frame.origin.y = CGRectGetMaxY(bounds) - frame.size.height;
frame.origin.x = 0;
_title.frame = frame;
// adjust the frame down for the image layout calculation
bounds.size.height = frame.origin.y - bounds.origin.y;
if ( (imageSize.width <= bounds.size.width) &&
(imageSize.height <= bounds.size.height) )
{
return;
}
// scale it down to fit
CGFloat hRatio = bounds.size.width / imageSize.width;
CGFloat vRatio = bounds.size.height / imageSize.height;
CGFloat ratio = MIN(hRatio, vRatio);
[_iconView sizeToFit];
frame = _iconView.frame;
frame.size.width = floorf(imageSize.width * ratio);
frame.size.height = floorf(imageSize.height * ratio);
frame.origin.x = floorf((bounds.size.width - frame.size.width) * 0.5);
frame.origin.y = floorf((bounds.size.height - frame.size.height) * 0.5);
_iconView.frame = frame;
}
#end
Now go into your main view or wherever this bookshelf will be. You need to adopt the AQGridView delegate and datasource
<AQGridViewDelegate, AQGridViewDataSource>
Then the delegate methods
- (NSUInteger) numberOfItemsInGridView: (AQGridView *) gridView
{
return (_array.count);
}
- (AQGridViewCell *) gridView: (AQGridView *) gridView cellForItemAtIndex: (NSUInteger) index
{
static NSString * EmptyIdentifier = #"EmptyIdentifier";
static NSString * CellIdentifier = #"CellIdentifier";
if ( index == _emptyCellIndex )
{
NSLog( #"Loading empty cell at index %u", index );
AQGridViewCell * hiddenCell = [gridView dequeueReusableCellWithIdentifier: EmptyIdentifier];
if ( hiddenCell == nil )
{
// must be the SAME SIZE AS THE OTHERS
// Yes, this is probably a bug. Sigh. Look at -[AQGridView fixCellsFromAnimation] to fix
hiddenCell = [[[AQGridViewCell alloc] initWithFrame: CGRectMake(0.0, 0.0, 155.0, 250.0)
reuseIdentifier: EmptyIdentifier] autorelease];
}
hiddenCell.hidden = YES;
return ( hiddenCell );
}
SpringBoardIconCell * cell = (SpringBoardIconCell *)[gridView dequeueReusableCellWithIdentifier: CellIdentifier];
if ( cell == nil )
{
cell = [[[SpringBoardIconCell alloc] initWithFrame: CGRectMake(0.0, 0.0, 250.0, 250.0) reuseIdentifier: CellIdentifier] autorelease];
}
UIImage * image = [UIImage imageNamed:#"Image.png"];
cell.icon = image;
return ( cell );
}
- (CGSize) portraitGridCellSizeForGridView: (AQGridView *) gridView
{
return ( CGSizeMake(250.0, 250.0) );
}
But when all is said and done, you want a bookshelf, so get a bookshelf image off of the internet. Then, crop it down so only ONE level of the shelf is showing. In AQGridview, the background with a pattern image will work perfectly, so in viewDidLoad, add in:
_gridView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"PatternImage.png"]];
The results produce a 250 X 250 cell with a cell title view, and a bottom title view. The icon for the cell, however, are the golden mean numbers of 155 X 250.
I don't know of any open source project, but you could use a background image for the newsstand frame itself. Then above that you may place a UIScrollView with a 'shelves' background image. From there I suppose you could add the individual news items as UIButtons or as part of a table view.
For this you can keep tableview where your Newstand title and button will go in header view and each cell will contain a book. Book will be a UIButton and u have to set a single rack image as a background for cell. Creating a custom cell will be beneficial. I dont prefer scroll view since there you need to manage the co-ordinates of each book and if you keep background as single image containing many racks then it will look like your books are floating across the racks.
https://github.com/AlanQuatermain/AQGridView
Try this one if u like. I took the logic from this and implemented my own grid.
UITable/ScrollView with pre-rendered bookshelf background?
Just use a picture of a bookshelf in the background.
Just use UIView (with background like bookshelf) and UITable (use custom (modify) cell for with shelf image). You don't need to use any ready made its very simple to build from scratch.