Why does my UIView subclass not redraw after I call setNeedsDisplay? - iphone

I have a custom UIView which is a sub-view of a UITableViewCell. When the cell is drawn, so is my custom view, correctly calling drawRect: in my UIView sub-class. When the cell is reloaded, the view is drawn correctly (drawRect: is called).
When a certain event happens (eg timer), I want to redraw the view without having to reload the whole cell. (This is not the only view in the cell.)
However, when I call setNeedsDisplay on my sub-view, nothing happens.
I'm guessing that when my view's drawRect: is called, the resulting image is cached in a backing somewhere such that when I call setNeedsDisplay that backing is redrawn to the screen, but my drawRect: call is never called again.
Why is drawRect: never called again after the cell is created?
EDIT: The cell's subviews are created from from a nib. ie: a UIViewController is loaded from the nib and its view is added to the UITableViewCell.
I made a test case from scratch with a custom view that isn't loaded from a nib (created by code) and it works as expected: setNeedsDisplay results in a drawRect: call. It must be something that's either set up in the .xib file or something that happens differently to a view when it's loaded from a nib.

I just ran into the same problem myself. For me it was an issue with my XIB - I am subclassing a UIView though - so adapt accordingly. My mistake in IB was that I attached my controls to the "file's owner" instead of attaching them to the UIView. I'm sure that in my inexperience there is something larger going on - perhaps someone with a bit more experience can elaborate.
Hope that helps!

Related

Using UIViewController with a UIView - (Want to use UIScrollView instead) - How to make the switch

I need to implement a scrolling window in order to accommodate all the items on the form I am creating. My current implementation is a UIViewController (that's vcAddCourse) and it has a UIView in it with my current form.
Here is what I have done to add the UIScrollView into the equation.
1) Using IB, I dragged a uiscrollview object 'into' the existing uiview object.
2) Using IB, Ctrl-dragged from file owner to the IBOutlet I created for the new uiscrollview
Here is how I init this controller.
3) I made sure that all the items on my form were now dragged to be under the UIScrollview object.
Finally, over in my .m file, in the ViewdidLoad() function, I added the following line:
theScroller.contentSize=CGSizeMake(328, 680);
No joy. I see the form but it does not scroll.
Note: this on iphone simulator.
What else must I do to swap out the UIView for the new UIScrollView?
Thanks!
To keep things like these clear, I keep the scrollView and the (larger) subview separate in the xib file (as siblings). Your form should be on a UIView, and would be larger than the scrollview. That way you can use IB to layout the form exactly as you want.
To make things work you just have to have the IBOutlets to the UIScrollView and the UIView, and add the view to the scrollview in the viewDidLoad method of your viewController:
[theScroller addSubView:formView];
I'm not exactly sure, but I don't think you have to set the contentSize manually after this, as it should automatically be made big enough to fit your view. If it's not working you might try this:
theScroller.contentSize = formView.frame.size;
Hope this helps

determine if uiview is displayed

is there a possibility to determine if an uiview obj is going to be displayed. imagine: you have 2 uiviews in an uiscrollview. now you are going to switch per gesture from the first view to the second. the first view now is NOT in the viewport. now you are going to go back to the first view. and now I want to be notified that this view is in viewport, or is redisplayed. the same has to be for the second view. I have not found any callback or something like this.
You make sure your UiViewController overrides viewWillAppear: (before it appears this method is called) or viewDidAppear: (after this method is called).
See: http://developer.apple.com/iphone/library/documentation/uikit/reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instm/UIViewController/viewWillAppear:
That depends what you mean by "switch". If one view is just scrolled out of the visible area of the scrollview, but still remains attached as a subview to it, then you may want to check if the bounds of your view overlap those of the scrollviews visible area.
You could do this by using UIScrollView Delegate's scrollViewDidScroll: method to implement a check for overlaps while the user is scrolling.
If however your view is actually removed from the viewstack, then you may want to subclass UIView and implement willMoveToSuperview: to check if the view has been added to the scrollview again.

LayoutSubviews for Custom UITableViewCell and UIView

I have a custom UITableViewCell. It has a UIView which is added to the "contentView" of the UITableViewCell. For any update, I'm redrawing that UIView by calling its "setNeedsDisplay" and implementing drawing inside "drawRect" method of the UIView.
The UITableViewCell overrides "willTransitionToState" and according to the bit mask value, asks the UIView to redraw.
Because I'm asking the UIView to redraw itself again, every time I do a "swipe to delete", I see the cell "flicker" a moment; even the text that didn't move position due to the Delete button suffers from a flicker since everything is being redrawn.
I'm aware that a possible solution is not to call "setNeedsDisplay" of the UIView from the "willTransitionToState" but instead call "setNeedsLayout" and have the UIView implement "layoutSubviews".
This is where I'm stuck at: how can I re-layout my UIView since everything inside my UIView is "drawn" (I use "drawInRect" and "drawAtPoint" methods for strings and images). There is also a string on the right side that I wanna hide when the "Delete" button appears (like in the Messages app in iPhone).
How can I do this by doing re-layout instead of re-draw?
Thank you!!!
I think there's an issue with your approach. Rather than draw everything, it's better to set up your subviews in an init method, or in the NIB.
In the willTransitionToState method, update whatever subviews according to the state transition.
In layoutSubviews, update each subview's origin and size as required.
Here's some detail from the willTransitionToState documentation. Although, I'm sure you'd have seen this already:
Subclasses of UITableViewCell can implement this method to animate additional changes to a cell when it is changing state. UITableViewCell calls this method whenever a cell transitions between states, such as from a normal state (the default) to editing mode. The custom cell can set up and position any new views that appear with the new state. The cell then receives a layoutSubviews message (UIView) in which it can position these new views in their final locations for the new state. Subclasses must always call super when overriding this method.

How do you update a secondary view?

Perhaps there's a better way to set this up so I'm open to suggestions.
But here's what I'm doing. I have a main UIView. On top of that I have a UIImageView and another UIView. When the UIImageView changes, I want to change the second UIView. So I have a class for it and the IB object's type is set to the class. In the .m of that class is a drawRect method that draws some rectangles. Also in the .m is a NSMutableArray property that is synthesized. I created an instance of that class in the controller of the main view.
The problem: despite the fact that the drawRect works fine when the app starts (as traced in the debugger,) when the UIImageView changes I call a "setNeedsDisplay" on the instance variable of the second view after updating the #synthesize'd array but the drawRect does not get called.
I think it has to do with instances. I wouldn't think threading would be an issue here. I just want to draw in a separate area of the screen based on an image also displayed.
OK, for those who see this and are having a similar issue...
It was indeed an 'instance' problem. I had created the secondary UIView in IB. I think because I had established a connection there, the code ran fine on startup.
The fix was to create the subview programmatically and add it to the main view. That way there was only the one instance. Updating the #synthesize'd array variable and the subsequent calls to drawRect (via setNeedsDisplay) went to the one instance of the secondary view, the one I had added as a subview to the main one. Problem solved.

iPhone custom UIView bounds

I am trying to create a custom UIView that is stored in a nib so that I can position it using Interface Builder.
I have created a class called RippleView that extends UIView. I'd like to position this view as a subview using Interface Builder. To do so, I've dragged a new view into my existing view in Interface Builder and gave it the RippleView class identity. I then linked my RippleView outlet to the view I just created.
In the RippleView class, I've implemented initWithCoder which doesn't do anything other than call [super initWithCoder...]. In awakeFromNib I go ahead and initialize my code.
Now, for some reason, if I try to check the bounds of the RippleView in awakeFromNib, I get ridiculous values (0 width and 1081171968 height). These bounds don't change in drawRect, so I don't think it's an issue of the view not being initialized. I get similar values in my touchesMoved event handler.
I had no problems when I was programmatically creating the subview (initWithFrame). What could be causing the frame bounds to go haywire?
Solved! The issue had nothing to do with the code. The UIView bounds are floats and I was printing them as integers. It's things like this that separate the programmers from the dropouts :p
Can you post your initWithCoder: implementation? If you're not setting the value of self, or if you've misspelled initWithCoder:, you might see these sorts of problems. Have you tried setting a breakpoint in initWithCoder: to make sure it gets called?