In my app I need to call some UIViews more than once. But in one of my method, i've a code like :
[self addSubview:UIImageView];
But i've read that addsubview method must be call once. So, to let the code how is it, how could I check if it's already on subview ? Like :
if ([UIImageView isOnSubview] == NO)
{
[self addSubview:UIImageView];
}
Because I don't find any method to check this :/
Thank you !
You are probably looking for UIView's -(BOOL)isDescendantOfView:(UIView *)view; taken in UIView class reference.
use this one
for (UIView *subview in [self subviews])
{
NSLog(#"%#", subview);
// ---------- remember one thing there should be one imageview ------
if(![subview isKindOfClass:[UIImageView class]])
{
[self addSubview:UIImageView];
}
}
Related
I have a bunch of UIViews that I subclassed that I have been adding to self.view e.g.:
MySpecialView *myView = [[MySpecialView alloc] init];
[self.view addSubview:myView];
Now I want to remove them all from self.view but only those custom ones. I don't want to remove any of the others (I have some other views with options in them etc). Is there anyway of doing this at all? Can I loop through all the subviews and check their type? Any pointers on this would be great! Thanks!
Try a loop like this
for (UIView *view in self.view.subviews)
{
if ([view isKindOfClass:[MySpecialView class]])
[view removeFromSuperview];
}
This simply iterates through all of the subviews and removes any that are of class MySpecialView.
Swift way
for subview in self.view.subviews {
if subview.isKindOfClass(MyClass) {
// Is that class!
} else if subview.isMemberOfClass(MyClass) {
// Is that class or a subclass of that class!
}
}
I'm trying to bringtofront my subview because the delete button keeps disappearing.
#implementation MyCell : UITableViewCell
- (void)layoutSubviews
{
[super layoutSubviews];
for (UIView *subview in self.subviews) {
for (UIView *subview2 in subview.subviews) {
NSLog(#"HERE!");
if ([NSStringFromClass([subview2 class]) isEqualToString:#"UITableViewCellDeleteConfirmationView"]) {
NSLog(#"got inside the if!");
[subview2 sendSubviewToBack:subview];
[subview bringSubviewToFront:subview2];
[self.superview bringSubviewToFront:subview2];
}
}
}
}
#end
I subclassed UITableViewCell. Both the NSLogs are printing so I know it's getting in there, but I've tried all 3 of these methods to put the view in front. Any ideas why this wouldn't be working?
subview2 is a subview of subview, which is a subview of self. The receiver of the sendSubviewToBack: or bringSubviewToFront: message must be the superview of the view given as argument. Therefore only the second one of the calls you make is valid. The correct calls would be
[self.superview bringSubviewToFront:self];
[self bringSubviewToFront:subview];
[subview bringSubviewToFront:subview2];
(And the same for sendSubviewToBack:.)
As for your actual problem, I can't figure out the view hierarchy you are using from the code posted, but it seems that it is incorrect. You should probably not have your custom views as direct subviews of self, but rather as subviews of self.contentView (as per Apple's documentation).
So I have a UIScrollView that is populated with a series of MyCustomViews that are subclasses of a standard UIView. In the delegate callback "scrollViewDidScroll I am trying to loop through all the subviews and call a specific function on them but I don't think the typecasting is working. Here is my code below:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
for(UIView *subView in [scrollView subviews){
MyCustomView *customView = (MyCustomView *)subView;
[customView myMethod];
}
}
When I call "myMethod" on customView, the program crashes saying an unrecognized selector was sent to instance. I believe that my type-casting is the issue as the method myMethod works in other situations. So how do I remedy this situation?
Solution 1:
If you do the following, you don't even need to cast your object to MyCustomView *. It can be of any type, e.g. UIView.
if([subView respondsToSelector:#selector(myMethod)]) {
[subView performSelector:#selector(myMethod)];
}
Solution 2:
You can check the object type before doing the cast.
if([subView isKindOfClass:[MyCustomView class]]) {
MyCustomView *customView = (MyCustomView *)subView;
[customView myMethod];
}
For "catch" this issue, use
if([customView respondsToSelector:#selector(myMethod)]){
[customView myMethod];
}
and with this, the app don't crash.
Also in your for use for(MyCustomView* customView in [scrollView subviews]){
I add some UIViews to my view using following method:
[self.view addSubview:myStickerView]; // this line is called every time when I select a button from ScrollView.
So, I can have a lot of myStickerView on my self.view.
Now, when I call this line: [myStickerView removeFromSuperview]; it will remove only my last myStickerView.
How can I remove all UIViews (myStickerView)?
The easiest way would be something like this:
for (UIView *view in self.view.subviews) {
if ([view isKindOfClass:[MYStickerView class]) {
[view removeFromSuperView];
}
}
Or you can store references for all inserted sticker views not to go through every subview
The easiest way would be to have an NSMutableArray property that kept track of your sticker views. When you add a sticker view to your view, add it to the array as well, that way you could do something like this when you wanted to remove all the sticker views
-(void)removeStickerViews
{
for(StickerView *stickerView in self.myStickerViewArray)
{
[stickerView doSomething];
[stickerView removeFromSuperview];
}
[self.myStickerViewArray removeAllObjects];
}
-(void)addStickerView:(StickerView *)inStickerView
{
[self.myStickerViewArray addObject:inStickerView];
[self.view addSubview:inStickerView];
}
The idea of keeping track in an array is fine, but I suggest using the more elegant [myArray makeObjectsPerformSelector:#selector(removeFromSuperview)] to achieve the result.
(my boss says) that I have to implement a "Done" button on a navBar so that the various items in the view (that contain an edit box) will dismiss their keyboard (if they were in focus).
It seems that I must iterate through all items and then call resignFirstResponder on each on the off-chance that one of them is in focus? This seems a bit messy (and hard to maintain if e.g. someone else adds more items in future) - is there a better way to do it?
I have found it!
Thanks to this
I discovered that all I need do is this:-
-(void) done {
[[self.tableView superview] endEditing:YES];
}
// also [self.view endEditing:YES]; works fine
[remark]
Also I learn how to do the equivalent of an "eventFilter" to stop UITableViewController from swallowing background touch events by intercepting them before they get there - from the same, wonderful post on that thread - see "DismissableUITableView".
[end of remark]
You don't have to iterate through the controls since only one can be first responder at the moment.
This will reset the responder to the Window itself:
[[self window] makeFirstResponder:nil]
One solution is to use a currentTextField Object,
In .h file have an instance variable as
UITextField *currentTextField;
Now in .m file.
Note : Dont forget to set the delegates of all the textField to this class
- (void)textViewDidBeginEditing:(UITextView *)textView
{
currentTextField = textField;
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
currentTextField = nil;
}
Now in your button action method
-(IBAction)buttonTap
{
if([currentTextField isFirstResponder])
[currentTextField resignFirstResponder];
}
This avoids iterating through all the text field.
I think best way to handle it by searching all subviews of main view with recursive function, check example below
- (BOOL)findAndResignFirstResponder {
if (self.isFirstResponder) {
[self resignFirstResponder];
return YES;
}
for (UIView *subView in self.subviews) {
if ([subView findAndResignFirstResponder]) {
return YES;
}
}
return NO;
}
and also you can put this method to your utility class and can use from tap gesture. All you have to do is simply adding to gesture to view.
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(hideEverything)];
[self.tableView addGestureRecognizer:gestureRecognizer];
and than you can call hideEverything method;
- (void) hideKeyboard {
[self.view findAndResignFirstResponder];
...
...
}