web-dev-qa-db-ja.com

ウィンドウ内のUIBarButtonItemフレームを把握しますか?

UIBarButtonItemUIViewを拡張しないため、フレームプロパティのようなものはありません。

しかし、アプリケーションCGRectに対して、UIWindowフレームとは何かを取得する方法はありますか?

64
leolobato

プライベートAPI sを使用しますか?そうであれば、

UIView* view = thatItem.view;
return [view convertRect:view.bounds toView:nil];

もちろん、AppStoreを対象とする場合、誰もこれを望みません。 より信頼性の低いメソッドであり、文書化されていない機能も使用しますが、Appleのテストに合格しますが、サブビューをループして対応するボタン項目を探します。

NSMutableArray* buttons = [[NSMutableArray alloc] init];
for (UIControl* btn in theToolbarOrNavbar.subviews)
  if ([btn isKindOfClass:[UIControl class]])
    [buttons addObject:btn];
UIView* view = [buttons objectAtIndex:index];
[buttons release];
return [view convertRect:view.bounds toView:nil];

indexは、.itemsの配列内のバー項目へのインデックスです。すべての空白項目を削除した後。このassumesボタンは昇順で配置されますが、そうでない場合があります。より信頼性の高い方法は、sortbuttons配列の.Origin.x値を増やすことです。もちろん、これはまだassumesバーボタン項目はUIControlクラスを継承する必要があり、ツールバー/ナビゲーションバーの直接のサブビューです。


ご覧のとおり、文書化されていない機能を扱う場合、多くの不確実性があります。ただし、指の下に何かをポップアップしたいだけですか? UIBarButtonItemの.actionは、次の形式のセレクターにすることができます。

-(void)buttonClicked:(UIBarButtonItem*)sender event:(UIEvent*)event;

event引数に注意してください—タッチの位置を取得するには

[[event.allTouches anyObject] locationInView:theWindow]

またはボタンビューで

[[event.allTouches anyObject] view]

そのため、サブビューを繰り返し処理したり、ドキュメント化されていない機能を使用したりする必要はありません。

126
kennytm

このオプションは掲載されていませんでした(私の意見ではもっと簡単です)。

UIView *barButtonView = [barButtonItem valueForKey:@"view"];
17
Carlos Guzman

IOS 3.2では、ツールバーボタンからアクションシートポップオーバーを表示するはるかに簡単な方法があります。このようなことだけをしてください:

- (IBAction)buttonClicked:(UIBarButtonItem *)sender event:(UIEvent *)event
{
 UIActionSheet *popupSheet;
 // Prepare your action sheet
 [popupSheet showFromBarButtonItem:sender animated:YES];
}
8
Jeremy Fuller

これは、WEPopoverプロジェクトに使用する実装です:( https://github.com/werner77/WEPopover ):

@implementation UIBarButtonItem(WEPopover)

- (CGRect)frameInView:(UIView *)v {

    UIView *theView = self.customView;
    if (!theView.superview && [self respondsToSelector:@selector(view)]) {
        theView = [self performSelector:@selector(view)];
    }

    UIView *parentView = theView.superview;
    NSArray *subviews = parentView.subviews;

    NSUInteger indexOfView = [subviews indexOfObject:theView];
    NSUInteger subviewCount = subviews.count;

    if (subviewCount > 0 && indexOfView != NSNotFound) {
        UIView *button = [parentView.subviews objectAtIndex:indexOfView];
        return [button convertRect:button.bounds toView:v];
    } else {
        return CGRectZero;
    }
}
@end
4

UIBarButtonItem(およびUITabBarItem)がUIViewから継承しない限り、歴史的な理由でUIBarItemNSObjectから継承します—この狂気は続きます(この記事の執筆時点では、iOS 8.2およびカウント...)

このスレッドの最良の答えは、明らかに @ KennyTM's です。愚かではなく、プライベートAPIを使用してビューを見つけます。

One_line Swift Origin.xソートされた配列( ケニーの答え が示唆するように):

    let buttonFrames = myToolbar.subviews.filter({
        $0 is UIControl
    }).sorted({
        $0.frame.Origin.x < $1.frame.Origin.x
    }).map({
        $0.convertRect($0.bounds, toView:nil)
    })

配列はOrigin.xUIBarButtonItemフレームでソート。

(他の人のUIBarButtonItemとの闘いについてもっと読む必要があると感じたら、 Ash Furrow's 2012年のブログ投稿: Exploring UIBarButtonItem

3
Erik Tjernlund
-(CGRect) getBarItemRc :(UIBarButtonItem *)item{
    UIView *view = [item valueForKey:@"view"];
    return [view frame];
}
2
Gank

Werner AltewischerのWEpopoverを動作させることができました。
UIBarButton:ModはWEPopoverController.mにあります

- (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)item toolBar:(UIToolbar *)toolBar
               permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections 
                               animated:(BOOL)animated 
{
    self.currentUIControl = nil;
    self.currentView = nil;
    self.currentBarButtonItem = item;
    self.currentArrowDirections = arrowDirections;
    self.currentToolBar = toolBar;

    UIView *v = [self keyView];
    UIButton *button = nil;

    for (UIView *subview in toolBar.subviews) 
    {
        if ([[subview class].description isEqualToString:@"UIToolbarButton"])
        {
            for (id target in [(UIButton *)subview allTargets]) 
            {
                if (target == item) 
                {
                    button = (UIButton *)subview;
                    break;
                }
            }
            if (button != nil) break;
        }
    }

    CGRect rect = [button.superview convertRect:button.frame toView:v];

    [self presentPopoverFromRect:rect inView:v permittedArrowDirections:arrowDirections animated:animated];
}
2
Jim Malak

UINavigationBarビューから取得できます。 navigationBarは、バー上のパーツに対して2つまたは3つのカスタム subviews を持つUIViewです。

UIBarButtonItemが現在右側のnavbarに表示されていることがわかっている場合、navbarのsubviews配列からフレームを取得できます。

まず、 navigationBar が必要です。これは navigationController から取得でき、UIViewControllerから取得できます。次に、最も適切なサブビューを見つけます。

UINavigationBar* navbar = curViewController.navigationController.navigationBar;
UIView* rightView = nil;

for (UIView* v in navbar.subviews) {
   if (rightView==nil) {
      rightView = v;
   } else if (v.frame.Origin.x > rightView.frame.Origin.x) {
      rightView = v;  // this view is further right
   }
}
// at this point rightView contains the right most subview of the navbar

このコードをコンパイルしていないので、YMMVです。

1
progrmr

これは最良の解決策ではなく、ある観点からは正しい解決策ではありません。また、UIBarBattonItem内のオブジェクトに暗黙的にアクセスするため、以下のようにすることはできませんが、次のようなことを試みることができます:

UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
[button setImage:[UIImage imageNamed:@"Menu_Icon"] forState:UIControlStateNormal];
[button addTarget:self action:@selector(didPressitem) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:button];
self.navigationItem.rightBarButtonItem = item;

CGPoint point = [self.view convertPoint:button.center fromView:(UIView *)self.navigationItem.rightBarButtonItem];
//this is like view because we use UIButton like "base" obj for 
//UIBarButtonItem, but u should note that UIBarButtonItem base class
//is NSObject class not UIView class, for hiding warning we implicity
//cast UIBarButtonItem created with UIButton to UIView
NSLog(@"point %@", NSStringFromCGPoint(point));

結果として、私は次になりました:

ポイント{289、22}

enter image description here

0
gbk