I have a class called LabelView inheriting from UIView. In the story board have a view dragged and inheriting from LabelView. Now I want to iterate through the self.superview to set the attributed text of each view. Please suggest a method to do so.
Here is my code:
int i=0;
for (UIView *view in labelView) {
if ([view isMemberOfClass:[LabelView class]]) {
[view setTag:i];
NSArray *symbols = #[#"+", #"-", #"*", #"/"];
NSString* symb = [NSString stringWithFormat:#"%#", [symbols objectAtIndex:i]];
UIFont *labelFont = [UIFont systemFontOfSize:view.bounds.size.width*0.80];
NSAttributedString *labelOperator=[[NSAttributedString alloc]initWithString:[NSString stringWithFormat:#"%#", symb]attributes:#{NSFontAttributeName: labelFont}];
CGRect textrect;
textrect.origin=CGPointMake(12, 0);
textrect.size=[labelOperator size];
[labelOperator drawInRect:textrect];
i++;
}
else{
NSLog(#"fail");
}
}
You may want to try something like this:
for (UIView *view in self.view.subviews) {
if ([view isMemberOfClass:[LabelView class]]) {
//DO WHATEVER YOU WANT
}
The above fast enumeration code iterates through all the subviews in your self.view and checks if the view is a member of your custom class which is LabelView. If it finds one, then the statements inside the if condition gets executed. Hope it helps!
The key is to go from your label view to the superview and iterate through its subviews.
for (UIView *label in labelView.superview.subviews) {
if ([label isKindOfClass:[LabelView class]]) {
// configure the label
}
}
Related
I have a single UIButton in the view of my UIViewController. I also have ten more that are in a subview in the main view. I want to find all these buttons. So far I have:
-(void)findAllButtons{
for(UIView *view in self.view.subviews) {
if ([view isKindOfClass:[myButton class]]){
NSLog(#"found a button!");
}
}
}
It is only finding the single button though and not the other ten. Why is that? Shouldn't it iterate every single subview and then find them?
for (UIView *subView in scroll.subviews) {
if ([subView isKindOfClass:[UIButton class]]) {
UIButton *btn = (UIButton*)subView;
if (btn.tag == selectedButton.tag) {
btn.layer.borderWidth = 1.0f;
btn.layer.borderColor = [UIColor darkGrayColor].CGColor;
}else{
btn.layer.borderWidth = 1.0f;
btn.layer.borderColor = [UIColor clearColor].CGColor;
}
}
}
Just a few lines of code
-(void)findAllButtons {
[self findButtonsInSubviews:self.view.subviews];
}
- (void)findButtonsInSubviews:(NSArray *)subviews {
for(UIView *view in subviews) {
if ([view isKindOfClass:[UIButton class]]){
NSLog(#"found a button!");
} else {
[self findButtonsInSubviews:view.subviews];
}
}
}
A recursive function using Objective-C blocks like this will find all views of a given subclass type as specified in the test block in the view hierarchy of the given view:
NSMutableArray *marrAllButtons = [NSMutableArray new];
BOOL (^viewTest)(UIView*) = ^BOOL(UIView* viewToTest) {
return [view isKindOfClass:[UIButton class]];
};
void(^viewEnumerator)(UIView*) = ^(UIView* outerView){
for (UIView *view in outerView.subviews)
{
if (viewTest(view))
{
[marrAllButtons addObject:view];
}
else
{
viewEnumerator(view);
}
}
};
viewEnumerator(self.view);
NSLog(#"All Buttons %#", marrAllButtons);
- (NSMutableArray *)buttonsInView:(UIView *)view
{
NSArray *subviews = view.subviews;
NSMutableArray *buttons = [NSMutableArray array];
for (UIView *subview in subviews)
{
if ([subview isKindOfClass:[UILabel class]])
{
[buttons addObject:subview];
}
else if(subview.subviews)
{
[buttons addObjectsFromArray:[self buttonsInView:subview]];
}
}
return buttons;
}
Your method is right if all your button already have in self.view (main view).
Just set tag for all button to check and also make sure that all button are on the main view. I hope this will work.
-(void)findAllButtons{
for(UIView *view in self.view.subviews) {
if ([view isKindOfClass:[myButton class]]){
UIButton *button = (UIButton*)view;
NSLog(#"found a button with tag:%d",button.tag);
}
}
}
for(UIView * subView in view.subviews) // here write Name of you ScrollView.
{
// NSLog(#"test %#", [subView class]);
if([subView isKindOfClass:[UIButton class]])
{
UIButton *button = (UIButton*)subView;
[button setSelected:NO] ;
NSString *s1;
s1 = #",";
s1 = [s1 stringByAppendingString:[NSString stringWithFormat:#"%#",button.titleLabel.text ]];
s1 = [s1 stringByAppendingString:[NSString stringWithFormat:#"%#",#"," ]];
NSRange range = [temp_Colors_Name_comma rangeOfString:s1 ];
if(range.location == NSNotFound)
{
}
else
{
[button setSelected:YES];
}
}
}
I am using the following to try to access all the UIButtons located inside of a UIScrollView within a UIView. The problem is that the code doesn't seem to locate the buttons and set the border property.
UIView -> UIScrollView -> UIButtons.
I basically want to loop through the buttons and set the border property.
for(UIView *v in [self.viewLightLeakChoices subviews]) {
if([v isKindOfClass:[UIButton class]]) {
v.layer.borderWidth = 0;
}
}
Try this one instead
for (id obj in scrollView.subviews) {
NSString *classStr = NSStringFromClass([obj class]);
if ([classStr isEqualToString:#"UIButton"]) {
UIButton *button = (UIButton*)obj;
button.layer.borderWidth = 2.0;
button.layer.borderColor = [UIColor greenColor].CGColor;
}
}
output
Thanks for the help guys. I ended up doing a bunch of for loops to get down to the UIButtons.
for(UIView *v in [self.viewLightLeakChoices subviews]) {
if([v isKindOfClass:[UIScrollView class]]) {
for(UIView *subView in [v subviews]) {
for(UIButton *btn in [subView subviews]) {
btn.layer.borderWidth = 0;
}
}
}
}
first make sure you are getting subviews of UIScrollView because your structure is
UIView > UIScrollView> UIButton
if you have only 1 scroll view in self.viewLightLeakChoices then set your scrollview tag = 1000 and direct access your scrollview so now you dont need to use loop. and execution will be fast.
UIScrollView *scrlV = [self.viewLightLeakChoices viewWithTag:1000];
for (UIButton *btn in scrlV.subviews)
{
if ([btn isKindOfClass:[UIButton Class]]) {
btn.layer.borderWidth = 1.0;
btn.layer.borderColor = [UIColor whiteColor].CGColor;
}
}
i am unable to get i am expecting you are having scrollview -> uiview ->button
for(UIView *myview in Scrollview.subviews)
{
for ( id mybutton in myview.subviews)
{
if ([mybutton isKindOfClass:[UIButton class]])
{
UIButton *mybtn=(UIButton *)mybutton;
mybtn.layer.borderWidth=0;
}
}
}
You should have create Button class say MyButton extents UIButton, if you do this there is no need to loop through scrollview's subviews.
implement awakeFromNib method and apply border, to apply border refer this SO Post How to create border in UIButton?
I have a UIScrollview in a tab, i added some UIView (NIB) to the UIScrollview. Each UIView has some UISwictch, labels, buttons, etc. How can i get the the label.text inside of the view added to the UIScrollview.
I tried a lot of things but i can access to the content of the UIView added to the UIScrollview.
Check with this,
for (UIView *addedView in [self.scrollView subviews])
{
for (UIView *sub in [addedView subviews])
{
if([sub isKindOfClass:[UILabel class]])
{
UILabel *myLabel = (UILabel *)sub;
NSLog(#"My label :%#",myLabel .text);
}
}
}
Here scrollView is your scroll view. It will print all label's text.
If you need to print any particular label's text. Then add a tag to it and check the tag before printing it, like if(myLabel.tag == 7)
set a unique tag for your label.
eg: label.tag = 10345 (some random number, which is a unique tag)
and you can search for the label in the parentView like this
UILabel *theLabel = (UILabel *)[parentView viewWithTag: 10345];
and then you can do what ever you want with the Label.
Step 1: Add this code in your scrollview
UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTap:)];
singleTapGestureRecognizer.numberOfTapsRequired = 1;
singleTapGestureRecognizer.enabled = YES;
singleTapGestureRecognizer.cancelsTouchesInView = NO;
[scrollView addGestureRecognizer:singleTapGestureRecognizer];
Step 2: Implement this method
-(void)singleTap:(UITapGestureRecognizer *)gesture
{
// Convert gesture into view for getting subviews
CGPoint point = [gesture locationInView:mainScrollView];
UIView *tappedView = [mainScrollView hitTest:point withEvent:nil];
// Get the subviews of the view
NSArray *subviews = [view tappedView];
// Return if there are no subviews
if ([subviews count] == 0) return;
for (UIView *subview in subviews) {
NSLog(#"%#", subview);
// List the subviews of subview
[self your_method:subview];
}
}
I need a way to get all UILabels within a UIView without having to go through all the views within the UIView.
I have many other type of views, UIButtons, UIImageViews and it would be too long to go through all of them when I just need the UILabels.
I'm trying to avoid something like this:
for (UIView *view in myView.subviews)
{
if([view isKindOfClass:[UILabel class]])
{
UILabel *lbl = (UILabel*)view;
}
}
Is it possible or am I dreaming?
Create an NSArray ivar which you can add all the UILabel's to.
If you do it in code then as you create the UILabel just do
NSMutableArray *labels = [[NSMutableArray alloc] init];
// Repeat this for al labels
UILabel *label = [[UILabel alloc] in...
[labels addObject:label];
// Then
self.labels = [labels copy];
If you use IB the declare your property like this
#property (nonatomic, strong) IBOutletCollection(UILabel) NSArray *labels;
and connect all the labels up to this.
Man, you need make use recursion. (If you don't want use tags)
Try This.
-(UIView *)checkChild:(UIView *)view{
NSArray *arrayView = view.subviews;
UIView *returnView = nil;
for (UIView *auxView in arrayView) {
if ([auxView isKindOfClass:[UILabel class]]) {
return auxView;
}else{
returnView = [self checkChild:auxView];
}
}
return returnView;
}
I liked the approach of #SiddharthaMoraes, but changed it to collect all the elements found on its path. I was looking for the UILabels inside my UIViewController and couldn't find them because they where nested inside another UIView, so this recursion should solve the problem:
-(NSMutableArray *)checkChild:(UIView *)view{
NSArray *arrayView = view.subviews;
NSMutableArray *arrayToReturn = [NSMutableArray new];
for (UIView *auxView in arrayView) {
if ([auxView isKindOfClass:[MyLabel class]]) {
[arrayToReturn addObject:auxView];
}else if( auxView.subviews ){
[arrayToReturn addObjectsFromArray:[self checkChild:auxView]];
}
}
return arrayToReturn;
}
You can set the tag property for the label.. something like this...
label.tag = 100;
UILabel *lbl = [yourView viewWithTag:100];
Which is the correct way of enumerating through sub views to find text fields?
NSMutableArray *mutableTFs = [[NSMutableArray alloc] init];
for (UIView *view in [self.view subviews]) {
if ([view isKindOfClass:[UITextField class]]) {
[mutableTFs addObject:view];
}
}
OR
NSMutableArray *mutableTFs = [[NSMutableArray alloc] init];
for (UITextField *textField in [self.view subviews]) {
[mutableTFs addObject:textField];
}
I know this isn't the correct wording, but what I don't understand is if it is the top method, how do you 'convert' it from a view to a text field?
Which is the correct way of enumerating through sub views to find text
fields?
The first method is the correct one. The second method will iterate over all the subviews, not just the subviews with type UITextField. The type in the for() is only a hint to the compiler.
For more information, see this question.
how do you 'convert' it from a view to a text field?
This is what typecasting is for.
for (UIView *view in [self.view subviews]) {
if ([view isKindOfClass:[UITextField class]]) {
// you don't need to cast just to add to the array
[mutableTFs addObject:view];
// typecasting works as it does in C
UITextField *textField = (UITextField *)view;
// do something with textField
}
}
The first method is the only working method of the two.
The second method would add all subviews to the array. That is if you would change subViews to subviews.
You could do the following:
for (UITextField *textField in [self.view subviews]) {
if ([textField isKindOfClass:[UITextField class]]) {
[mutableTFs addObject:textField];
}
}
That way you wouldn't have to convert the view to a text field to do something text field specific instead of just adding it to an array.
EDIT: If you don't want to convert to a text field right away, maybe because you're looking for both text fields and text views. This is how you'd convert it later:
for (UIView *view in [self.view subviews]) {
if ([view isKindOfClass:[UITextField class]]) {
UITextField *textField = (UITextField *)view;
// Do whatever you want with the text field.
}
if ([view isKindOfClass:[UITextView class]]) {
UITextView *textView = (UITextView *)view;
// Do whatever you want with the text view.
}
}
Here's the best way.
// Make sure you're releasing this!
NSMutableArray *textFields = [[NSMutableArray alloc] init];
for (UITextField *textField in [self.view subviews]) {
if ([textField isKindOfClass:[UITextField class]]) {
[textFields addObject:textField];
}
}
By specifying UITextField * as the type that you're performing the fast enumeration with, you'll be working with values that are casted already (by fast enumeration) from id to UITextField *. This does not guarantee that they are actually UITextFields though, so you still need a runtime check, in this case isKindOfClass:, to make sure the object you're currently working is really a UITextField.
So, both of them are correct, but only when combined.