I have been trying to create a grid on the iPhone of 16x16 images.
- (void)viewDidLoad {
[super viewDidLoad];
int xLocation = 0;
for (int i=0; i <= 619; i++) {
if (((i % 30) == 0) && i != 0) { //if at end of column (30th row), moves x over 16 px to next column
xLocation += 16;
}
else {;}
CGRect imageRect = CGRectMake( xLocation, (16*i), 16, 16);
UIImageView *image = [[UIImageView alloc] initWithFrame:imageRect];
[image setImage:[UIImage imageNamed:#"Untitled-1.png"]];
[image setOpaque:YES];
NSLog(#"%d", xLocation);
[self.view addSubview:image];
[image release];
}
The problem is the int xLocation. For some reason, CGRectMake uses 0 in the x-coordinate slot instead of xLocation. I say "instead of" because the NSLog below it reveals that the xLocation has the values that I want it to, so the assignment of the values is working fine. What is going on here?
Casting xLocation as an int in your NSLog will certainly work, but you could also use:
NSLog(#"imageRect %#", NSStringFromCGRect(imageRect));
There are a whole series of NSStringFromXXX helper functions that come in handy from time to time.
The xLocation is 0 for the first column and it is being increased for each column but the y coordinate is not being reset to 0 for each new column. It just keeps increasing based on i. So the columns from the second onward are just off screen at the right xLocation but a high y value.
Try changing the imageRect calculation to:
CGRect imageRect = CGRectMake( xLocation, (16*(i % 30)), 16, 16);
%d doesn't present float's properly. Use %f or convert xLocation to an int:
NSLog(#"%d", (int)xLocation);
You can also simplify your xLocation calculation readability by calculating it each time, something like
16 * (i / 30)
The overhead is minimal on modern processors.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
Alright, so I have 5 custom images total.
Heres the values I need to set each image to:
Image1 = 1
Image2 = 2
Image3 = 3
Image4 = 4
Image5 = 5
I need values assigned to these because I want to have xcode randomly place them on the view until it reaches a value of 50. So im assuming I need some kind of loop that adds up the values until 50 is reached?
How do I assign values to these images since it brings up a warning when trying to assign an int value to a UIImage. Also, on a side note what method would I use to randomly place the images on the view without overlapping?
Thanks for any and all help!
Your app will be placing UIImageViews, not UIImages onto a view. Like all UIView subclasses, UIImageView has an NSInteger tag property, but if I understand the problem correctly, I don't think you need that, either.
// add count randomly selected images to random positions on self.view
// (assumes self is a kind of UIViewController)
- (void)placeRandomImages:(NSInteger)count {
for (NSInteger i=0; i<count; ++i) {
UIImage *image = [self randomImage];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = [self randomFrameForImage:image];
[self.view addSubview:imageView];
// add a tag here, if you want, but I'm not sure what for
// imageView.tag = i;
}
}
// answer a random image from the app's bundle
// assumes the images are named image-x where x = 0..4
- (UIImage *)randomImage {
NSInteger imageNumber = arc4random() % 5;
NSString *imageName = [NSString stringWithFormat:#"image-%d", imageNumber];
return [UIImage imageNamed:imageName];
}
// answer a random position for the passed image, keeping it inside the view bounds
- (CGRect)randomFrameForImage:(UIImage *)image {
CGFloat imageWidth = image.width;
CGFloat imageHeight = image.height;
CGFloat maxX = CGRectGetMaxX(self.view.bounds) - imageWidth;
CGFloat maxY = CGRectGetMaxY(self.view.bounds) - imageHeight;
// random location, but always inside my view bounds
CGFloat x = arc4random() % (NSInteger)maxX;
CGFloat y = arc4random() % (NSInteger)maxY;
return CGRectMake(x,y,imageWidth,imageHeight);
}
If want to assign an arbitrary integer value, I would use the tag property on UIImageView.
NSInteger currentTag = 50;
while (currentTag > 0) {
UIImageView *imageView = [UIImageView alloc initWithImage:image];
imageView.tag = currentTag;
[self.view addSubView:imageView];
currentTag--;
}
Put the images into an NSArray then from NSHipster:
How Do I Pick a Random Element from an NSArray
Use arc4random_uniform(3) to generate a random number in the range of a non-empty array.
if ([array count] > 0) {
id obj = array[arc4random_uniform([array count])];
}
I am drawing cells from a grid with a NSTimer every 0.1 Seconds.
The size is about 96x64 => 6144 cells / images.
If i am drawing images instead of (e.g.) green rectangles it is 4 times slower !
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
UIGraphicsPushContext(context);
CGContextSetRGBFillColor(context, 0, 0, 0, 1);
CGContextFillRect(context, CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height));
int cellSize = self.bounds.size.width / WIDTH;
double xOffset = 0;
for (int i = 0; i < WIDTH;i++)
{
for (int j = 0; j < HEIGHT;j++)
{
NSNumber *currentCell = [self.state.board objectAtIndex:(i*HEIGHT)+j];
if (currentCell.intValue == 1)
{
[image1 drawAtPoint:CGPointMake(xOffset + (cellSize * i),cellSize * j )];
}
else if (currentCell.intValue == 0){
[image2 drawAtPoint:CGPointMake(xOffset + (cellSize * i),cellSize * j )];
}
}
}
UIGraphicsPopContext();
}
Any idea how to makes this faster if i want to draw png or jpg in each rectangle?
The images are already scaled to an appropriate size.
a) Don't redraw the images/rects that are outside the view's bounds.
b) Don't redraw the images/rects that are outside the dirtyRect
c) Don't redraw the images/rects that haven't changes since the
previous update.
d) Use a layer to prerender the images, so you don't need to render
them at drawing time.
This scenario is exactly what Instruments is there for. Use it. Anyone here making a suggestion is guessing about what the bottleneck is.
That said, I'm going to guess at what the bottleneck is. You are drawing 6114 images using the CPU (confirm this by using the time profiler. Find your drawRect method, and check where the most time is spent. If it's drawInRect, then that's your problem)
If that's the case, how do we reduce its usage? An easy win would be to only redraw the images we need to draw. CALayers make this easy. Remove your drawRect method, add a sublayer to your view's layer for each image, and set the images as your layers' content properties. Instead of invalidating the view when an image needs to change, just switch the relevant layer's content property to the new image.
Another nice thing about CALayers is that they cache layer content on the GPU, meaning that the redraws that do happen will require less CPU time and won't block the rest of you app as much when they do happen.
If the overhead of that many layers is unacceptable (again, Instruments is your friend), check out CAReplicatorLayer. It's less flexible than having many CALayers, but allows a single image to be replicated many times with minimal overhead.
I tried to improve your code from performance perspective. However, check my comment about bottlenecks, too.
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
//UIGraphicsPushContext(context); //not needed UIView does it anyway
//use [UIView backgroundColor] instead of this
//CGContextSetRGBFillColor(context, 0, 0, 0, 1);
//CGContextFillRect(context, CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height));
int cellSize = self.bounds.size.width / WIDTH;
double xOffset = 0;
CGRect cellFrame = CGRectMake(0, 0, cellSize, cellSize);
NSUinteger cellIndex = 0;
for (int i = 0; i < WIDTH; i++) {
cellFrame.origin.x = xOffset;
for (int j = 0; j < HEIGHT; j++, cellIndex++) {
cellFrame.origin.y = 0;
if (CGRectIntersectsRect(rect, cellFrame) {
NSNumber *currentCell = [self.state.board objectAtIndex:cellIndex];
if (currentCell.intValue == 1) {
[image1 drawInRect:cellFrame];
}
else if (currentCell.intValue == 0) {
[image2 drawInRect:cellFrame];
}
}
cellFrame.origin.y += cellSize;
}
cellFrame.origin.x += cellSize;
}
//UIGraphicsPopContext(context); //not needed UIView does it anyway
}
Use CGRectIntersects to check if the rect of your image is inside the dirtyRect to check if you need to draw it.
I want to create a grid of rectangles at the centre of screen leaving some space on the edges. The need of that arises because I am spewing different sprites at random points and they keep spawning on top of eat other. So i thought if there is a way of creating a class that creates the grid and returns me with a random rect and mark it occupied as long at the sprite stays in that rect and make it free after.
If i can get some help or any tips it will be great. Any other solutions to achieve this are welcome too.
Thanks.
You could nest two for loops, one for rows and one for columns, make them both run 5 times, and in each loop increment the x position and y position by one-fifth the width and height of the screen and put these coordinates into a CGRrect. That would do what you want.
Thanks #andrewx for your help. This will create CGRect in the given range and then return a random one.
-(void) makeCGRectArray{
rectsArray = [[NSMutableArray alloc] init];
for (int x = 30; x<=420; x= x+60) {
for (int y=40; y<=280; y=y+40) {
CGRect newRect = CGRectMake(x, y, 60, 40);
[rectsArray addObject:[NSValue valueWithCGRect:newRect]];
}
}
[self getRandomCgrect:rectsArray];
}
-(CGRect) getRandomCgrect:(NSMutableArray*) rectArray{
NSInteger randomPoint = (arc4random() % (49));
CGRect randomRect = [[rectsArray objectAtIndex:randomPoint] CGRectValue];
self.isOccupied = YES;
return randomRect;
}
i want to display many images like thumbnails in a scroll view and and i want the images displayed dynamically we scrolls down or left like a table view cells
can u please tell how to that...
Thanks
with the following code..when we scroll the scroll view im calling this code and able to display the images dynamically (which r only visible) but the problem is.. while scrolling with scroll bars im getting the two images..vertically and horizontally..its only happening when i scroll.. can any body help me out please..?
int tileSize;
int imgSize;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
tileSize = 255;
imgSize = 247;
}else{
tileSize = 120;
imgSize = 116;
}
CGRect visibleBounds = [songsContainer bounds];
for (UIView *tile in [songsContainer subviews]) {
CGRect scaledTileFrame =[tile frame];
if (! CGRectIntersectsRect(scaledTileFrame, visibleBounds)) {
for(UIView *view in [tile subviews])
[view removeFromSuperview];
[recycledCells addObject:tile];
[tile removeFromSuperview];
}
}
int maxRow =[songsDict count]-1; // this is the maximum possible row
int maxCol = noOfRowsInCell-1; // and the maximum possible column
int firstNeededRow = MAX(0, floorf(visibleBounds.origin.y / tileSize));
int firstNeededCol = MAX(0, floorf(visibleBounds.origin.x / tileSize));
int lastNeededRow = MIN(maxRow, floorf(CGRectGetMaxY(visibleBounds) / tileSize));
int lastNeededCol = MIN(maxCol, floorf(CGRectGetMaxX(visibleBounds) / tileSize));
NSLog(#".........MaxRow-%d,MaxCol-%d,firstNeddedRow-%d,firstNeededcol-%d,lNR-%d,lNC%d",maxRow, maxCol, firstNeededRow,firstNeededCol,lastNeededRow,lastNeededCol);
// iterate through needed rows and columns, adding any tiles that are missing
for (int row = firstNeededRow; row <= lastNeededRow; row++) {
NSMutableArray *tempArray = (NSMutableArray *)[songsDict objectAtIndex:row];
for (int col = firstNeededCol; col <= lastNeededCol ; col++) {
BOOL tileIsMissing = (firstVisibleRow > row || firstVisibleColumn > col ||
lastVisibleRow < row || lastVisibleColumn < col);
if (tileIsMissing) {
UIView *tile = (UIView *)[self dequeueReusableTile];
if (!tile) {
// the scroll view will handle setting the tile's frame, so we don't have to worry about it
tile = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
tile.backgroundColor = [UIColor clearColor];
}
//tile.image = image for row and col;
// set the tile's frame so we insert it at the correct position
CGRect frame = CGRectMake(tileSize * col, tileSize * row, imgSize, imgSize);
tile.frame = frame;
if(col<[tempArray count])
[self addContentForTile:tile:row:col];
else tile.backgroundColor = [UIColor clearColor];
[songsContainer addSubview:tile];
}
}
}
firstVisibleRow = firstNeededRow+1; firstVisibleColumn = firstNeededCol+1;
lastVisibleRow = lastNeededRow; lastVisibleColumn = lastNeededCol;
What you have to do is create your scrollview however you want. You have to decide whether you want a grid layout, or linear layout. In addition, if grid, do you want it locked to the horizontal bounds, locked to vertical, so it scrolls either vertical or horizontal, respectively.
Once you have that sorted out, then what I recommend is taking the architecture similar to how a tableview functions. That is, create individual "cells" that will hold your thumbnails. Once you have these cells, you add them as subviews of your scrollview, at certain offsets (you need to do some math on the x/y planes).
Start with a scroll view and add each image in an UIImageView as a subview to the scrollview at a certain location.
One thing to have in mind is to only hold in memory the images that are currently shown and their immediate neighbours.
I'm trying to place the icons / images horizontally in a view that is intended to show details. Maximum number of pictures per row is 6 pieces and I want to have a mechanism that manage line breaks or similar automatically. I suspect it is a custom cell that solves this?
I have tried the following code below, but the images above to add another when I reload the view. Furthermore, the cell's height is not adjusted by the view that the code returned.
-(UIImageView *)fillView{
collage = nil;
collage = [[[UIImageView alloc] initWithFrame:CGRectMake(11, 7, 0, 0)] autorelease];
int rowCounter = 0;
int colCounter = 0;
int nrOfPictures = [paymentImages count];
//max 6 images per row
while (nrOfPictures > 0) {
while (colCounter <= 6 && nrOfPictures != 0) {
UIImageView *iv = [[UIImageView alloc] initWithImage:[paymentImages objectAtIndex:nrOfPictures-1]];
CGRect frame = iv.frame;
frame.origin.x = (frame.size.width + 4) * colCounter;
frame.origin.y = (frame.size.height + 4) * rowCounter;
iv.frame = frame;
[collage addSubview:iv];
[iv release];
colCounter++;
nrOfPictures--;
if (colCounter > 6) {
colCounter = 0;
rowCounter++;
}
}
}
return collage;
}
Can someone head me in the right direction?
You might want to check out this project. http://github.com/kirbyt/KTPhotoBrowser