how to add subviews from array to a uiview? - iphone

i have my subviews stored in an array...what i want is to place these subviews to my main view from array....
for(int i=0;i<[imageViewArray count];i++)
{
NSLog(#" image array count is %d",[imageViewArray count]);
// countlayers= countlayers+1;
// [canvasView insertSubview:[imageViewArray objectAtIndex:i] atIndex:countlayers];
[canvasView addSubview:[imageViewArray objectAtIndex:i]];
}
can you tell me what i am doing wrong

If imageViewArray really contains initialized views, and if those views already have correct frame attributes, you're doing nothing wrong (even though your code could be more elegant).
Also, of course, we have to make sure that canvasView is indeed initialized and visible on the screen. Try setting its backgroundColor to something noticeable:
canvasView.backgroundColor = [UIColor greenColor];
Once you are sure the canvasView is actually being displayed, I would suggest using fast enumeration, which makes going through the array nicer, and logging your new subviews to make sure their frames are like you want them.
for (UIView *imageView in imageViewArray) //this is fast enumeration. You can get it through code completion by typing forin
{
NSLog(#"%#", imageView); //let's take a look at the imageView. What is its frame?
[canvasView addSubview:imageView];
}

Used enumeration to add images on your canvas View using imageViewArray and probably you are also missing with the setting frame of the images.
for (UIImageView *imageView in imageViewArray) //enumeration.
{
//let's set frame for image view before adding to canvasView
[imageView setFrame:CGRectMake(x,y,w,h)];
//Also make sure imageView has image or not
if(imageView.image)
[canvasView addSubview:imageView];
}

Related

Scrolling Images From NSMutableArray

I parse an XML in my blog app. When I parse it, I have created an object called entry, with properties for Title, Article, Link, Content, and Image. I then have a mutable array called entries that after parsing is finished, I add to entries the object entry. This way, to get the Title of a certain article in a tableview, I can call
RSSEntry *entry = [_Entries objectAtIndex:indexPath.row];
NSString *title = entry.Title;
What I would like to do is have a UIImageView above the tableview, and set that to scroll through all the different UIImages in the array, but am unsure of how to accomplish this. I know of the animationImages property, but not sure what to set as the NSArray in all this, since I use Mutable Array with properties. Any suggestions would greatly help.
There are two options:
a) collect all the images in the separate array by iterating through _Entries to set the animationImages array value;
b) prepare your own view, initialize the timer at constructor with [NSTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:], change the displayed image at selector. To make a smooth animation you can use two imageView subviews setting animated the displayed imageView alpha from 1 to 0 and the next imageView alpha from 0 to 1. As the datasource you can use array of RSSEntry* taking the images from there with a known keypath.
The first option is fairly easier.
I hope you know how to put the UIImageView above the tableview in the xob/storyboard.
Than I am not sure what would you like to do with array of images, but if that mets your needs than it can be a swipe recognizer, and swipe the images
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
UISwipeGestureRecognizer* recognizerLeft = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeLeft)];
recognizerLeft.direction =UISwipeGestureRecognizerDirectionLeft;
recognizerLeft.numberOfTouchesRequired =1;
[self.view addGestureRecognizer:recognizerLeft];
[recognizerLeft release];
UISwipeGestureRecognizer* recognizerRight = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeRight)];
recognizerRight.direction =UISwipeGestureRecognizerDirectionRight;
recognizerRight.numberOfTouchesRequired =1;
[self.view addGestureRecognizer:recognizerRight];
[recognizerRight release];
}
- (IBAction)swipeLeft{
//NSLog(#"Swipe left");
if(pager.currentPage < pager.numberOfPages - 1){
pager.currentPage = (pager.currentPage + 1 );
[self pagerValueChanged];
}
}
- (IBAction)pagerValueChanged
{
NSData* imgData = [images objectAtIndex:pager.currentPage];
UIImage* img = [[UIImage alloc]initWithData:imgData];
imageView.image = img;
//NSLog(#"img width: %f, img height: %f", img.size.width, img.size.height);
[img release];
}
I have paging control and other controls too in my code, but you probably don't need those
This is pretty easy using array enumeration. The following code will take a scroll view that you have already configured and add image views to it for all the objects in your array. It will also dynamically adjust the content size of the scroll view based on the count of the array.
[myMutableArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
UIImageView *myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[myMutableArray objectAtIndex:idx]]];
[myImageView setFrame:CGRectMake(myScrollView.frame.size.width * idx, myScrollView.frame.origin.y, myScrollView.frame.size.width, myScrollView.frame.size.height)];
[myScrollView addSubview:myImageView];
[myScrollView setContentSize:CGSizeMake((myScrollView.frame.size.width * idx) + myScrollView.frame.size.width, myScrollView.frame.size.height)];
}];

Program crashes when loading 200+ subview images in the UIScrollView

I am developing a similar program like Photos in the iPhone using ALAssetLibrary. I am trying to load the images in a scrollview. Everything works fine when the album has small amount of pictures. But when I trying to load the album with 200+ photos, my program ended without any error message. Anyone know this program?
Here is my code for loading scroll view:
- (void)loadScrollView
{
for (UIView *v in [scrollview subviews]) {
[v removeFromSuperview];
}
CGRect scrollFrame = [self frameForPagingScrollView];
scrollview = [[UIScrollView alloc] initWithFrame:scrollFrame];
CGRect workingFrame = scrollview.frame;
workingFrame.origin.y = 0;
photoCount = [info count];
for(NSDictionary *dict in info) {
UIImageView *imageview = [[UIImageView alloc] initWithImage:[dict objectForKey:UIImagePickerControllerOriginalImage]];
[imageview setContentMode:UIViewContentModeScaleAspectFit];
imageview.frame = workingFrame;
[scrollview addSubview:imageview];
[imageview release];
[scrollview setPagingEnabled:YES];
[scrollview setDelegate:self];
[scrollview setAutoresizesSubviews:YES];
[scrollview setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
[scrollview setShowsVerticalScrollIndicator:NO];
[scrollview setShowsHorizontalScrollIndicator:NO];
workingFrame.origin.x = workingFrame.origin.x + workingFrame.size.width;
}
[self setScrollViewContentSize];
[[self view] addSubview:scrollview];
}
Thanks a lot in advance!!!
I personally put all of my UIImageView objects on my UIScrollView, but only set the image property for them for those that are currently visible (and clear the image property for those that are no longer visible). If you have thousands of images, perhaps even that is too wasteful (perhaps you don't even want to keep the UIImageView objects, even without their image property set, around), but if you're dealing with hundreds, I find it is a nice easy solution, addressing the key problem of the memory consumed by the UIImage objects:
- (void)viewDidLoad
{
[super viewDidLoad];
self.scrollView.delegate = self;
// all of my other viewDidLoad stuff...
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self loadVisibleImages];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self loadVisibleImages];
}
- (void)loadVisibleImages
{
CGPoint contentOffset = self.scrollView.contentOffset;
CGRect contentFrame = self.scrollView.bounds;
contentFrame.origin = contentOffset;
for (UIImageView *imageView in _imageViews) // _imageViews is (obviously) my array of images
{
if (CGRectIntersectsRect(contentFrame, imageView.frame))
{
imageView.image = ... // set the image property
}
else
{
imageView.image = nil;
}
}
}
This is a snippet from some code that's doing a bunch of other stuff, so clearly your implementation will differ significantly, but it shows how you can use scrollViewDidScroll to determine what images are visible and load/unload images appropriately. You could probably alter further if you want to also remove/add the UIImageView objects, too, but clearly the logic of "is this imageview visible" would have to be changed, rather than leveraging the frame of all of the UIImageView objects.
I'm not sure if I'm reading your code right, but do you also have all of your UIImage objects sitting in a dictionary, too? That's pretty extravagant use of memory, itself. I usually keep the actual images in some persistent store (e.g. I use Documents folder, though you could use Core Data or SQLite, though the latter two impose a significant performance hit for large images). The only images I keep in memory are the ones actively used by the UI and I'll use a NSCache object to keep a few around for performance reasons, but I otherwise pull them from persistent storage, not active memory.
You should use scroll view delegation to determine which images would be showing on the screen at the current time, and only have those loaded in memory.
Also, if you are displaying a much smaller than the actual image size, you should resize the image and use the smaller image.
why not use UICollectionView and UICollectionViewController classes? UICollectionViewController reference here
sample code here.
Your images will end up being instances of UICollectionViewCell. The data source and delegate protocol methods are similar to the UITableView methods. i.e. they provide a mechanism where the UICollectionViewController will reuse the UICollectionViewCells.
The benefit of using these classes is that they are used similarly to UITableViewControllers and they assist you with the memory pressure issues that you are having.
good luck!

Updating UIImage within arrayed UIImageview

I can now display a UIImageView that is within an array but using the following:
[[self.guess objectAtIndex:1] setFrame:CGRectMake(20, 20, 100, 100)];
[self.view addSubview:[self.guess objectAtIndex:1]];
If I want to change the image within one of my UIImageViews within the array
I can use:
[self.guess replaceObjectAtIndex:1 withObject:Square];
but I then have to remove the original view, then add the new subview again:
[[self.guess objectAtIndex:1] removeFromSuperview];
[self.view addSubview:[self.guess objectAtIndex:1]];
The trouble is, my new subview does not inherit the frame position and size
of the original image (as this may have changed). Is there a way to do this
more easily?
I was hoping for something like this, that would just update the original
image in the same position, with the same size:
[self.guess.image replaceObjectAtIndex:1 withObject:Square.image];
Thanks again!
Would it be possible to store only the images in the array and just have one UIImageView? Then, just replace the image inside the UIImageView element
What Radu already said, its better to keep an array of images, or imageNames. Then you also do not have to remove the imageView from the superView, you just reuse the one and only one ImageView.
So what you left is something like this
yourImageView.image = [self.guess objectAtIndex:1];
And if you only store the names in the array
yourImageView.image = [UIImage imageNamed:[self.guess objectAtIndex:1]];
I don't if you've tried this yet, but this should work.
UIImageView *img = (UIImageView *)[self.guess objectAtIndex:1];
img.image = Your Image;

Image in reused cell in a TableView not being cleared from ImageVIew

I have a Tableview containing cells with images, however the cells that are reused still contain the image from the previous cell that is being reused until the new image is downloaded and set.
I have tried setting the image to nil. (imageV is a subclass of HJManagedImageV, source can be found here: HJManagedImageV
[cell.imageV setImage:nil];
the setter
-(void)setImage:(UIImage *)theImage{
if (theImage==image) {
//when the same image is on the screen multiple times, an image that is alredy set might be set again with the same image.
return;
}
[theImage retain];
[image release];
image = theImage;
[imageView removeFromSuperview];
self.imageView = [[[UIImageView alloc] initWithImage:theImage] autorelease];
[self addSubview:imageView];
[imageView setNeedsLayout];
[self setNeedsLayout];
[loadingWheel stopAnimating];
[loadingWheel removeFromSuperview];
self.loadingWheel = nil;
self.hidden=NO;
if (image!=nil) {
[callbackOnSetImage managedImageSet:self];
}
}
I have a workaround for by setting imageV to hidden but then I lose the loading spinner and I'd really like to know why setting it to nil isn't working.
Anyone have any ideas, cause I'm all out of them. Or am I missing a step somewhere.
Are the cells a subclass of UITableViewCell? If yes, I would try to implement the method prepareForReuse and see if can solve the problem there.
Hope this helps =)
Don't set it to nil, nor hide it.
We use a similar class and what we do for such cases is to set a start image to be displayed until the new image loads.
So in your case you could simply set the image as a blank jpg/png inside your bundle instead of nil

What's wrong with my Checkbox drawing?

I built a UIButton subclass that is a very basic checkbox. Everything is working (e.g. I'm getting the events I expect, the drawRect method is called when I expect, etc), but my image isn't drawing. I've checked that my image is not nil and that my images are different.
Code:
-(void)awakeFromNib {
[super awakeFromNib];
[self addTarget:self action:#selector(buttonClick) forControlEvents:UIControlEventTouchUpInside];
self.state=YES;
}
-(void) buttonClick {
self.state = !self.state;
[self setNeedsDisplay];
}
-(void)drawRect:(CGRect)rect {
UIImage *img = nil;
if (self.state) {
img = [self backgroundImageForState:UIControlStateSelected];
}
else {
img = [self backgroundImageForState:UIControlStateNormal];
}
[img drawInRect:rect];
}
Checking the value of 'img' before it is drawn:
Printing description of img:
<UIImage: 0x52a710>
(gdb) continue
Printing description of img:
<UIImage: 0x52a5d0>
The background images are being set in the NIB. If I change the selected state in IB, I see the proper image show up. I'm also getting a valid image back from the call (which I don't if I try to get imageForState, which is not set in the NIB).
The reason for the subclass is that I need a checkbox. UIButton doesn't do that and UISwitch is hideously ugly for all but the most utilitarian views.
Thoughts?
Thanks.
tj
Edit: Added all the code for the subclass
Where are you setting backgroundImageForState? Are you sure it's the correct image? iPhone OS might be giving you a transparent (blank) image as a default.
Second, I wouldn't use the passed-in "rect" param to draw the image. That's just telling you the area it wants you to redraw, not necessarily anything else. Instead use
CGRectMake(0, 0, img.size.width, img.size.height)
or something similar.
Finally, why are you doing custom drawing? I've done something very similar, and you absolutely don't need to subclass and implement drawRect. UIButton has an extremely rich set of options built in for images, including "highlighted" and "selected" images that will draw automatically with user interaction. Let us know what you need to accomplish.
Just because the UIImage isn't nil doesn't mean it contains image data.
Check the case of your file name.
I've done this several times:
#"CheckBox.png" and #"checkbox.png" are 2 different names to the iPhone.
It seems you may be doing a little premature optimizing as well.
I wouldn't dive into drawRect: for my first option.
Use a UIButton subclass (you only need to subclass to track state). Set the button up in IB and position it where you want it. Connect the button to the method below and simply swap the images on the click:
- (IBAction)toggle:(id)sender{
MyButtonSubClass *aButton = (MyButtonSubClass*)sender;
[aButton toggleChecked];
if(aButton.checked)
[aButton setImage:checkedImage forState:UIControlStateNormal];
else
[aButton setImage:uncheckedImage forState:UIControlStateNormal];
}
optionally you can not subclass UIButton and track state in the controller