ios 自定义标签栏上的更多菜单

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/438381/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:32:25  来源:igfitidea点击:

Customizing the More menu on a Tab bar

iosiphoneuitabbarcontroller

提问by Ian1971

I am using a tab bar (UITabBarController) on my app and I wish to customize the appearance of the table that appears when you click the more button. I have worked out how to change the appearance of the Navigation bar that is on the more screen by setting

我在我的应用程序上使用标签栏 (UITabBarController),我希望自定义单击更多按钮时出现的表格的外观。我已经解决了如何通过设置更改更多屏幕上导航栏的外观

self.moreNavigationController.navigationBar.barStyle

in a subclass of UITabBarController and I have managed to change the background colour of the table by modifying

在 UITabBarController 的子类中,我设法通过修改来更改表格的背景颜色

self.moreNavigationController.topViewController.view.backgroundColor

, but I cannot work out how to change the font colour in the cells that appear on the table. I was hoping I could use

,但我无法弄清楚如何更改出现在表格中的单元格中的字体颜色。我希望我可以使用

self.moreNavigationController.topViewController.view.visibleCells 

but this always seems to be empty. I've tried doing this in viewDidLoad, viewWillAppear and viewDidAppear with no success. The object self.moreNavigationController.topViewController is of type UIMoreListController, which seems to be undocumented and I can't see anything obvious in the interface that will help me.

但这似乎总是空的。我试过在 viewDidLoad、viewWillAppear 和 viewDidAppear 中这样做,但没有成功。对象 self.moreNavigationController.topViewController 是 UIMoreListController 类型,它似乎没有记录,我在界面中看不到任何明显的东西可以帮助我。

Any ideas?

有任何想法吗?

回答by Ian1971

Following on from Stephan's suggestion to replace the dataSource of the moreNavigationController, here is a quick over view of the code I implemented.

继 Stephan 建议替换 moreNavigationController 的 dataSource 之后,这里是我实现的代码的快速概览。

I created a new class called MoreTableViewDataSource which implements the UITableViewDataSource protocol. The controller which the more page actually uses to build the table is called the UIMoreListControllerModern, and this implements just the required parts of the UITableViewDataSource protocol. My implementation looks like this.

我创建了一个名为 MoreTableViewDataSource 的新类,它实现了 UITableViewDataSource 协议。更多页面实际用于构建表格的控制器称为 UIMoreListControllerModern,它仅实现了 UITableViewDataSource 协议的必需部分。我的实现看起来像这样。

-(MoreTableViewDataSource *) initWithDataSource:(id<UITableViewDataSource>) dataSource
{
    self = [super init];
    if (self)
    {
            self.originalDataSource = dataSource;
    }

    return self;
}

- (void)dealloc
{
    self.originalDataSource = nil;
    [super dealloc];
}

- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
{
    return [originalDataSource tableView:table numberOfRowsInSection:section];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [originalDataSource tableView:tableView cellForRowAtIndexPath:indexPath];
    cell.textColor = [UIColor whiteColor];
    return cell;
}

and then in my CustomTabBarController class I override viewDidLoad as follows:

然后在我的 CustomTabBarController 类中,我按如下方式覆盖 viewDidLoad:

- (void)viewDidLoad {

    [super viewDidLoad];

    UINavigationController *moreController = self.moreNavigationController;
    moreController.navigationBar.barStyle = UIBarStyleBlackOpaque;

    if ([moreController.topViewController.view isKindOfClass:[UITableView class]])
    {

        UITableView *view = (UITableView *)moreController.topViewController.view;
        view.backgroundColor = [UIColor blackColor];
        moreTableViewDataSource = [[MoreTableViewDataSource alloc] initWithDataSource:view.dataSource];
        view.dataSource = moreTableViewDataSource;

    }
}

As requested here are the header files

根据这里的要求是头文件

@interface MoreTableViewDataSource : NSObject <UITableViewDataSource>
{
    id<UITableViewDataSource> originalDataSource;
}

@property (retain) id<UITableViewDataSource> originalDataSource;

-(MoreTableViewDataSource *) initWithDataSource:(id<UITableViewDataSource>) dataSource;

@end

and

#import "MoreTableViewDataSource.h"

@interface CustomTabBarController : UITabBarController 
{
    MoreTableViewDataSource *moreTableViewDataSource;
}

回答by Stephan Burlot

visibleCells is populated only after the moreNavigationController is displayed.

只有在显示 moreNavigationController 之后才会填充visibleCells。

And the cells are created at runtime, so even if you change the content of the cells, they are replaced when they are displayed.

并且单元格是在运行时创建的,因此即使您更改单元格的内容,它们也会在显示时被替换。

One thing to try would be to replace the datasource of the moreNavigationController tableView, call the cellForRowAtIndexPath of the original datasource and change its content before returning it.

要尝试的一件事是替换 moreNavigationController tableView 的数据源,调用原始数据源的 cellForRowAtIndexPath 并在返回之前更改其内容。

Using the code below, after having displayed once the moreNavigationController to initialize it, you'll see that when you return to the moreNavigationController, the cells are red, but return immediately to white background.

使用下面的代码,在显示一次 moreNavigationController 对其进行初始化之后,您会看到当您返回 moreNavigationController 时,单元格是红色的,但立即返回到白色背景。

UITableView *view = (UITableView *)self.tabBarController.moreNavigationController.topViewController.view;
if ([[view subviews] count]) {
  for (UITableViewCell *cell in [view visibleCells]) {
    cell.backgroundColor = [UIColor redColor];
  }
}

回答by rudald

Thanks to Unknown. Following his solution, I will put his code in Swift. Only what you should do more is create MoreTableViewCell class and just it. You don't have to use Storyboard. If you want to modify tableView you can do it in customizeMoreTableView method.

感谢未知。按照他的解决方案,我将把他的代码放在 Swift 中。只有你应该做的更多是创建 MoreTableViewCell 类,就这样。您不必使用故事板。如果你想修改 tableView,你可以在 customMoreTableView 方法中进行。

class TabBarMenuController: UITabBarController, UITableViewDelegate, UITableViewDataSource{

var tabBarItems: [UIViewController] = []
var areMessagesVisible: Bool = false

var titleForTabBars: [String] = ["resources", "events", "training", "my profile", "news", "contacts"]
var iconNames: [String] = ["film", "calendar", "classroom", "profile", "news", "Phone"]
var controllersStoryboardId: [String] = ["resourcesNavController", "eventsNavController", "enablementNavController", "profileNavController", "newsNavController", "contactsNavController"]

// to manage moreTableView
var moreTableView: UITableView = UITableView()
var currentTableViewDelegate: UITableViewDelegate?

override func viewDidLoad() {
    super.viewDidLoad()

    self.customizeMoreTableView()
    //to REMOVE
    areMessagesVisible = true

    if !areMessagesVisible{
        self.titleForTabBars.removeAtIndex(4)
        self.controllersStoryboardId.removeAtIndex(4)
        self.iconNames.removeAtIndex(4)
    }

    for i in 0 ..< controllersStoryboardId.count{
        tabBarItems.append(UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier(controllersStoryboardId[i]) as? UINavigationController ?? UINavigationController())
    }
    self.moreNavigationController.navigationBar.tintColor = UIColor.blackColor()
}

override func viewWillAppear(animated: Bool) {

    for i in 0 ..< tabBarItems.count{
        tabBarItems[i].tabBarItem = UITabBarItem(title: titleForTabBars[i], image: UIImage(named: iconNames[i]), selectedImage: UIImage(named: iconNames[i]))
    }
    self.viewControllers = tabBarItems
}

func customizeMoreTableView(){
    moreTableView = self.moreNavigationController.topViewController!.view as? UITableView ?? UITableView()
    currentTableViewDelegate = moreTableView.delegate;
    moreTableView.delegate = self
    moreTableView.dataSource = self;
    moreTableView.registerClass(MoreTableViewCell.self, forCellReuseIdentifier: "MoreTableViewCell")

}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let moreCell  = tableView.dequeueReusableCellWithIdentifier("MoreTableViewCell", forIndexPath: indexPath) as? MoreTableViewCell ?? MoreTableViewCell()

    moreCell.textLabel?.text = titleForTabBars[indexPath.row + 4]
    moreCell.imageView?.image = UIImage(named: iconNames[indexPath.row + 4])

    /*let testLabel: UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 40))
    testLabel.backgroundColor = UIColor.yellowColor()
    moreCell.addSubview(testLabel)
    */
    return moreCell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return titleForTabBars.count - 4
}

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    currentTableViewDelegate?.tableView!(tableView, didSelectRowAtIndexPath: indexPath)
}

 }

回答by wickning1

I followed Ian's implementation to customize the More menu, but I was having a problem retaining the customizations after a memory warning. didReceiveMemoryWarning seems to destroy the UITableView, and when it is regenerated it gets its old dataSource back. Here's my solution:

我按照 Ian 的实现来自定义“更多”菜单,但是在出现内存警告后保留自定义设置时遇到问题。didReceiveMemoryWarning 似乎破坏了 UITableView,当它重新生成时,它会取回旧的数据源。这是我的解决方案:

I replace viewDidLoad on the CustomTabBarController with this:

我用这个替换了 CustomTabBarController 上的 viewDidLoad:

- (void)viewDidLoad {
    [super viewDidLoad];
    UINavigationController* moreController = self.moreNavigationController;
    if ([moreController.topViewController.view isKindOfClass:[UITableView class]]) {
        moreController.delegate = self;
        self.moreControllerClass = [moreController.topViewController class];
        UITableView* view = (UITableView*) moreController.topViewController.view;
        self.newDataSource = [[[MoreDataSource alloc] initWithDataSource:view.dataSource] autorelease];
    }
}

As you can see, I added a few properties for storing things I needed. Those have to be added to the header and synthesized. I also made CustomTabBarController a UINavigationControllerDelegate in the header. Here's the delegate function I added:

如您所见,我添加了一些属性来存储我需要的东西。这些必须添加到标题中并合成。我还在标题中将 CustomTabBarController 设为 UINavigationControllerDelegate。这是我添加的委托函数:

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if ([viewController isKindOfClass:self.moreControllerClass]) {
        UIView* view = self.moreNavigationController.topViewController.view;
        if ([view isKindOfClass:[UITableView class]]) {
            UITableView* tview = (UITableView*) view;
            tview.dataSource = self.newDataSource;
            tview.rowHeight = 81.0;
        }
    }
}

This way I make sure my custom data source is always used, because I set it that way just prior to showing the UIMoreListController, every time it's shown.

通过这种方式,我确保始终使用我的自定义数据源,因为我在每次显示 UIMoreListController 之前就以这种方式设置它。

回答by Cyklet

@interface TabBarViewController () <UITableViewDelegate,UITableViewDataSource>

@property (nonatomic,strong) UITableView* tabBarTableView;
@property (nonatomic,weak) id <UITableViewDelegate> currentTableViewDelegate;

@end

@implementation TabBarViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self costumizeMoreTableView];

}

-(void)costumizeMoreTableView{
    _tabBarTableView = (UITableView *)self.moreNavigationController.topViewController.view;
    _currentTableViewDelegate = _tabBarTableView.delegate;
    _tabBarTableView.delegate = self;
    _tabBarTableView.dataSource = self;
    [_tabBarTableView registerNib:[UINib nibWithNibName:@"MoreTabBarTableViewCell" bundle:nil] forCellReuseIdentifier:@"MoreTabBarTableViewCell"];

}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 120;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 2;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    MoreTabBarTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MoreTabBarTableViewCell" forIndexPath:indexPath];
    [cell setMoreTableValues];
    return cell;
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath{
      [_currentTableViewDelegate tableView:tableView didSelectRowAtIndexPath:indexPath];
 }

 @end

回答by TvNuland

This works for me in iOS 13, Swift 5.1:

这在 iOS 13 Swift 5.1 中对我有用:

extension MyTabBarController: UITabBarControllerDelegate {
    // handle a select of the More tab
    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
        // style all the tab bar windows and the More tab bar tableview
        if viewController == moreNavigationController,
            let moreTableView = moreNavigationController.topViewController?.view as? UITableView {
            view.tintColor = .systemOrange
            moreNavigationController.navigationBar.tintColor = .systemOrange
            moreTableView.tintColor = .systemOrange
            moreTableView.backgroundColor = UIColor(named: "Your Color")
            moreTableView.visibleCells.forEach {
                ##代码##.backgroundColor = UIColor(named: "Your Color")
            }
        }
    }
}