UITabBarItem
で特定のUITabBar
のフレームを見つける方法はありますか?
具体的には、タブの1つに「落ちる」画像のアニメーションを作成します。メールでメールを削除するか、iTunesアプリでトラックを購入する。したがって、アニメーションのターゲット座標が必要です。
私の知る限りでは、座標を取得するためのパブリックAPIはありませんが、それについて誤解したいと思います。その前に、タブバーフレームに対する特定のタブのインデックスを使用して座標を推測する必要があります。
Imreの実装には、2つの重要な詳細が欠けています。
だから私は彼のコードを少し変更し、これを思いつきました:
+ (CGRect)frameForTabInTabBar:(UITabBar*)tabBar withIndex:(NSUInteger)index
{
NSMutableArray *tabBarItems = [NSMutableArray arrayWithCapacity:[tabBar.items count]];
for (UIView *view in tabBar.subviews) {
if ([view isKindOfClass:NSClassFromString(@"UITabBarButton")] && [view respondsToSelector:@selector(frame)]) {
// check for the selector -frame to prevent crashes in the very unlikely case that in the future
// objects thar don't implement -frame can be subViews of an UIView
[tabBarItems addObject:view];
}
}
if ([tabBarItems count] == 0) {
// no tabBarItems means either no UITabBarButtons were in the subView, or none responded to -frame
// return CGRectZero to indicate that we couldn't figure out the frame
return CGRectZero;
}
// sort by Origin.x of the frame because the items are not necessarily in the correct order
[tabBarItems sortUsingComparator:^NSComparisonResult(UIView *view1, UIView *view2) {
if (view1.frame.Origin.x < view2.frame.Origin.x) {
return NSOrderedAscending;
}
if (view1.frame.Origin.x > view2.frame.Origin.x) {
return NSOrderedDescending;
}
NSAssert(NO, @"%@ and %@ share the same Origin.x. This should never happen and indicates a substantial change in the framework that renders this method useless.", view1, view2);
return NSOrderedSame;
}];
CGRect frame = CGRectZero;
if (index < [tabBarItems count]) {
// viewController is in a regular tab
UIView *tabView = tabBarItems[index];
if ([tabView respondsToSelector:@selector(frame)]) {
frame = tabView.frame;
}
}
else {
// our target viewController is inside the "more" tab
UIView *tabView = [tabBarItems lastObject];
if ([tabView respondsToSelector:@selector(frame)]) {
frame = tabView.frame;
}
}
return frame;
}
UITabBarのタブバー項目に関連付けられているサブビューは、UITabBarButtonクラスです。 2つのタブを持つUITabBarのサブビューをログに記録することにより:
for (UIView* view in self.tabBar.subviews)
{
NSLog(view.description);
}
あなたが得る:
<_UITabBarBackgroundView: 0x6a91e00; frame = (0 0; 320 49); opaque = NO; autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x6a91e90>> - (null)
<UITabBarButton: 0x6a8d900; frame = (2 1; 156 48); opaque = NO; layer = <CALayer: 0x6a8db10>>
<UITabBarButton: 0x6a91b70; frame = (162 1; 156 48); opaque = NO; layer = <CALayer: 0x6a8db40>>
これに基づくと、解決策は簡単なものです。これを試すために私が書いた方法は次のとおりです。
+ (CGRect)frameForTabInTabBar:(UITabBar*)tabBar withIndex:(NSUInteger)index
{
NSUInteger currentTabIndex = 0;
for (UIView* subView in tabBar.subviews)
{
if ([subView isKindOfClass:NSClassFromString(@"UITabBarButton")])
{
if (currentTabIndex == index)
return subView.frame;
else
currentTabIndex++;
}
}
NSAssert(NO, @"Index is out of bounds");
return CGRectNull;
}
UITabBarの構造(サブビュー)とクラスUITabBarButton自体はパブリックAPIの一部ではないため、理論的には事前通知なしに新しいiOSバージョンで変更される可能性があることに注意してください。それでも、そのような詳細が変更される可能性は低く、iOS 5-6以前のバージョンでは問題なく機能します。
別の可能ながずさんな解決策は次のようになります:
guard let view = self.tabBarVC?.tabBar.items?[0].valueForKey("view") as? UIView else
{
return
}
let frame = view.frame
Swift 4.2:
private func frameForTab(atIndex index: Int) -> CGRect {
var frames = view.subviews.compactMap { (view:UIView) -> CGRect? in
if let view = view as? UIControl {
return view.frame
}
return nil
}
frames.sort { $0.Origin.x < $1.Origin.x }
if frames.count > index {
return frames[index]
}
return frames.last ?? CGRect.zero
}
extension UITabBar {
func getFrameForTabAt(index: Int) -> CGRect? {
var frames = self.subviews.compactMap { return $0 is UIControl ? $0.frame : nil }
frames.sort { $0.Origin.x < $1.Origin.x }
return frames[safe: index]
}
}
extension Collection {
subscript (safe index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}
タブバーボタンは、ユーザー操作が有効になっている唯一のサブビューです。非表示のAPIに違反しないようにするには、UITabBarButtonの代わりにこれを確認してください。
for (UIView* view in self.tabBar.subviews)
{
if( [view isUserInteractionEnabled] )
{
[myMutableArray addObject:view];
}
}
配列に入ると、Origin xに基づいて並べ替えると、タブバーボタンが正しい順序で配置されます。
私の単純なUITabBarControllerシナリオで機能したものを追加します。すべてが合法ですが、項目の間隔が等しいことが前提となっています。 iOS7では、UITabBarButtonのインスタンスを返しますが、UIView *として使用する場合は、それが何であるかを気にせず、クラスを明示的に指定していません。返されたビューのフレームは、探しているフレームです。
-(UIView*)viewForTabBarItemAtIndex:(NSInteger)index {
CGRect tabBarRect = self.tabBarController.tabBar.frame;
NSInteger buttonCount = self.tabBarController.tabBar.items.count;
CGFloat containingWidth = tabBarRect.size.width/buttonCount;
CGFloat originX = containingWidth * index ;
CGRect containingRect = CGRectMake( originX, 0, containingWidth, self.tabBarController.tabBar.frame.size.height );
CGPoint center = CGPointMake( CGRectGetMidX(containingRect), CGRectGetMidY(containingRect));
return [ self.tabBarController.tabBar hitTest:center withEvent:nil ];
}
それが行うことは、ボタンが存在するUITabBarで四角形を計算し、この四角形の中心を見つけ、その時点でビューをhitTest:withEventを介して掘り下げることです。
Swift + iOS 11
private func frameForTabAtIndex(index: Int) -> CGRect {
guard let tabBarSubviews = tabBarController?.tabBar.subviews else {
return CGRect.zero
}
var allItems = [UIView]()
for tabBarItem in tabBarSubviews {
if tabBarItem.isKind(of: NSClassFromString("UITabBarButton")!) {
allItems.append(tabBarItem)
}
}
let item = allItems[index]
return item.superview!.convert(item.frame, to: view)
}
Swift 5:
これを、タブバーを処理するビューコントローラーに配置するだけです。
guard let tab1frame = self.tabBar.items![0].value(forKey: "view") as? UIView else {return}
次にそのように使用します:
let tab1CentreXanc = tab1frame.centerXAnchor
let tab1CentreY = tab1frame.centerYAnchor
let tab1FRAME = tab1frame (centerX and Y and other parameters such as ".origins.x or y"
お役に立てば幸いです。
他のタブからパラメータを参照する場合は、インデックスを[0]から好きなものに変更してください
タブバーを初期化するとき、それにタグを付けます:
let tabItem = UITabBarItem(title: "my title", image: nil, tag: 1000)
次に、以下を使用してタブバーを取得できます。
let myTabItem = tabBarController?.tabBar.viewWithTag(1000)
プライベートAPIは必要ありません。UITabbarプロパティitemWidth
およびitemSpacing
を使用してください。これらの2つの値を次のように設定します。
NSInteger tabBar.itemSpacing = 10; tabBar.itemWidth = ([UIScreen mainScreen].bounds.size.width - self.tabBarController.tabBar.itemSpacing * (itemsCount - 1)) /itemsCount;
これは、UITabBarItemに使用される画像とタイトルのサイズまたは位置には影響しません。
そして、次のようにith
アイテムの中心xを取得できます。
CGFloat itemCenterX = (tabBar.itemWidth + tabBar.itemSpacing) * ith + tabBar.itemWidth / 2;