简而言之:
当导航控制器的返回按钮标题更改时,在某些情况下,旧标题会卡住,新标题将不会显示。这只发生在一些可重现的情况下,而在其他情况下,它按设计工作。
这取决于硬件
- 错误发生在iPhone 3G(iOS 4.2.1)和模拟器(iOS 5.1)上
- 使用相同的源代码,在iPhone 4(iOS 5.1)上没有错误
这取决于写入标题的单词
- 当按钮被创建时,从我自己编写的创建方法中获取与上一个在导航控制器堆栈上的页面相同的标题,如果其他条件匹配,则尝试在以后更改按钮的标题时,旧文本会被固定,新标题将不会显示出来。
- 当按钮在创建时获取与其默认标题不同的单词作为标题时,以后的每次更改都可以正常工作,只要不将默认标题分配给它即可。
- 如果在成功更改了许多不同标题的情况下,将字词放在按钮的标题上,这是其默认标题,则该字词会被固定。稍后的更改将不会被接受(没有任何消息,只有在其他条件匹配的情况下)
这取决于按钮在此期间是否隐形。
- 如果导航控制器的栈上推入了另一个视图,以使带有错误按钮的旧页面被新页面隐藏,并且稍后从堆栈中弹出新页面,使按钮再次可见(并且其他情况匹配),则旧文本将被卡住,试图更改它将被忽略(没有任何消息)。
- 如果按钮从未被隐藏,则更改其标题永远不会有问题。它总是有效的。
正确的标题在动画期间可见
- 当尝试更改返回按钮的标题由于上述情况的组合而被忽略时,当单击此返回按钮并处理页面向右滑动动画时,适当的标题仍然会在约0.3秒钟内变得可见。在动画开始时,旧的卡住的标题被正确的标题替换,正确的标题在动画期间可见。
详细描述
这是关于 UINavigationController
返回按钮上的文本问题。我根据新的语言设置更改此按钮的标题。目前我的应用程序在导航控制器堆栈中最多有3个视图控制器。它们中的每一个都是 `UITableViewController` 的不同子类。
表1,名为 GeneralTableVC
是堆栈上的根视图。它没有返回按钮。它向用户提供了存储在应用程序内的内容摘要,并显示带有设置按钮的工具栏。
提供在表1中可见的工具栏的是导航控制器。在表2和3中将其设置为不可见。目前该工具栏中只有一个名为“设置”的按钮。触摸此设置按钮将把表2推送到堆栈上。
表2,名为 SettingsTabVC
有一个返回按钮,在模拟器中会出现问题,但在运行iOS 5.1的真实iPhone 4上正常工作。
通过触摸表2的第一行,将创建一个新的表(表3)并将其推送到堆栈上。
表格3名为LangSelectTableVC
,也有一个返回按钮,但这个按钮在iPhone模拟器和真实的iPhone 4设备中都能很好地工作。
表格3是一个语言选择表格,显示所有可用语言(目前只有英语和德语)的列表。触摸行会立即更改设置。活动视图(表格3)将被重新绘制,在几毫秒内屏幕上的所有文本都将以新语言显示。
重新绘制表格本身并不是问题,导航栏中的标题也是如此。但是返回按钮上的文本也必须进行翻译,这有点棘手。我已经在两个返回按钮上使用了完全相同的技巧,对于指向表格2的按钮在表格3上可见,它可以很好地工作。但是,使用完全相同的代码,模拟器上的指向表格1的按钮存在问题(但真实的iPhone上没有问题)。
我给你一些代码片段和一些截图,以展示我所做的和发生的情况:
源代码
使用ARC(自动引用计数)。
我定义了一个重绘协议:
Protocols.h
#ifndef ToDo_Project_Protocols_h
#define ToDo_Project_Protocols_h
@protocol redrawProt
- (void) mustRedraw;
@end
#endif
这是表格1的标题:
GeneralTableVC.h
#import <UIKit/UIKit.h>
#import "Protocols.h"
// some other imports
@interface GeneralTabVC : UITableViewController <redrawProt>
@property id<redrawProt> parent;
@property Boolean mustRedrawMyself;
@property NSString* backTitle;
@property UIBarButtonItem* myBackButton;
@property UIBarButtonItem* parBackButton;
- (id) initWithParent:(id<redrawProt>)par andBackTitle:(NSString*)bT andBackButton:(UIBarButtonItem*)bB;
@end
其他表的头文件,
SettingsTabVC.h
和 LangSelectTabVC.h
定义了相同的属性和相同的初始化函数。程序从这里开始: AppDelegate.m 的一部分
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// some code
GeneralTabVC* genTabCon = [[GeneralTabVC alloc] initWithParent:nil andBackTitle:nil andBackButton:nil];
UINavigationController* navCon = [[UINavigationController alloc] initWithRootViewController:genTabCon];
// some other code
}
接下来是Table1的实现(
GeneralTableVC.m
)。表2(SettingsTabVC.m
)和表3(LangSelectTabVC.m
)中的代码类似。我不显示实现协议UITableViewDataSource的代码部分,因为我认为这些部分并不重要来解释问题。在这段代码中,您将找到宏
LocalizedString(keyword)
,它与NSLocalizedString(keyword,comment)
完全相同,可以将关键字翻译成所需的语言。我的版本使用不同的包进行翻译(而不是主包)。
GeneralTableVC.m
#import "GeneralTabVC.h"
#import "SettingsTabVC.h"
#define MYTITLE @"summary"
id<redrawProt> parent;
Boolean mustRedrawMyself;
NSString* backTitle;
UIBarButtonItem* myBackButton;
UIBarButtonItem* parBackButton;
@interface GeneralTabVC ()
@end
@implementation GeneralTabVC
@synthesize parent, mustRedrawMyself, backTitle, myBackButton, parBackButton;
- (void) mustRedraw {
self.mustRedrawMyself = YES;
}
- (void) redraw {
if ((self.parBackButton) && (self.backTitle)) {
// Important!
// here I change the back buttons title!
self.parBackButton.title = LocalizedString(self.backTitle);
}
if (self.parent) {
[self.parent mustRedraw];
}
self.title = LocalizedString(MYTITLE);
[self.tableView reloadData];
self.mustRedrawMyself = NO;
}
- (id) initWithParent:(id<redrawProt>)par andBackTitle:(NSString*)bT andBackButton:(UIBarButtonItem *)bB {
self = [super initWithStyle:UITableViewStyleGrouped];
if (self) {
self.parent = par;
self.mustRedrawMyself = NO;
self.backTitle = bT;
self.parBackButton = bB;
}
return self;
}
- (void) toolbarInit {
// this method exists only in Table 1, not in other tables
// it creates a UIBarButtonItem, adds it to self.toolbarItems
// and makes it visible
}
- (void)SettingsAction:(id)sender {
// this method exists only in Table 1, not in other tables
// it will be executed after the user tabs on the settings-
// button in the toolbar
SettingsTabVC* setTabCon = [[SettingsTabVC alloc] initWithParent:self andBackTitle:MYTITLE andBackButton:self.myBackButton];
[self.navigationController pushViewController:setTabCon animated:YES];
}
- (void) viewDidLoad {
[super viewDidLoad];
self.title = LocalizedString(MYTITLE);
// I want an Edit-Button. Localization of this button is
// not yet done. At the moment is uses the systems language,
// not the apps language.
self.navigationItem.rightBarButtonItem = self.editButtonItem;
[self toolbarInit];
}
- (void) viewWillAppear:(BOOL)animated {
// this is an important method! Maybe here is the reason for
// my problem!
[super viewWillAppear:animated];
// When ever this controllers view is going to appear, and
// when ever it is necessary to redraw it in a new language,
// it will redraw itself:
if (self.mustRedrawMyself) {
[self redraw];
}
// And here comes the buggy back button:
// When ever this controllers view is going to appear,
// a new back button will be created with a title in the
// new language:
UIBarButtonItem* BB = [[UIBarButtonItem alloc] init];
BB.title = LocalizedString(MYTITLE);
self.myBackButton = BB;
self.navigationItem.backBarButtonItem = self.myBackButton;
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// show toolbar:
[self.navigationController setToolbarHidden:NO animated:YES];
}
// next methods are about InterfaceOrientation and the
// UITableViewDataSource protocoll. They are not important
// for the problem.
// but maybe the very last method is important. It comes in
// different versions in the three implementation files:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// This is the version of GeneralTableVC.m (Table 1)
// It does nothing (at the actual stage of expansion, in later
// versions it will start the main business logic of this app)
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// This is the version of SettingsTableVC.m (Table 2)
// Tabbing onto row 0 of section 0 will push the
// language-selection-table (Table 3) on screen:
if (indexPath.section == 0) {
if (indexPath.row == 0) {
// create Table 3:
LangSelectTabVC* langTabCon = [[LangSelectTabVC alloc] initWithParent:self andBackTitle:MYTITLE andBackButton:self.myBackButton];
[self.navigationController pushViewController:langTabCon animated:YES];
} else {
// do something else (nothing at this stage of expansion)
}
} else {
// do something else (nothing at this stage of expansion)
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// This is the version of LangSelectTableVC.m (Table 3)
// here I do some magic to select and store the new language.
// Part of this magic is transforming indexPath.row
// into a valid language-code, putting it into the
// settings-object, and registering this object to
// NSUserDefaults
}
@end
截图
在iPhone 5.1模拟器上启动应用程序将在屏幕上显示表格1 (GeneralTableVC
):
现在我们切换到第一行(“
Language English >
”):
一切都很好。
现在让我们改变语言。点击 "German
" 标签:
哇!现在一切都是德语了。甚至后退按钮也从“设置”变成了“Einstellungen”。
让我们点击那个“Einstellungen”后退按钮:
几乎一切都很好了;一切都变成了德语。除了返回按钮,它仍然显示“Summary”而不是“Überblick”。我不明白为什么,因为当我在我的真正的iPhone 4上使用完全相同的步骤和源代码时,最后一个屏幕看起来像这样: 请注意后退按钮上的文字。在真正的 iPhone 4 上,它是德语单词“Überblick”(这就是我想要的),但在模拟器中,它是英语单词“Summary”。 这对我来说意味着,在某些手机上(像我的 iPhone 4),用户得到了预期的结果,但是在一些其他手机上(也许是 iPhone 4S),用户会得到一个有错误的显示。有人有什么关于我的代码出了什么问题的想法吗?
编辑
编辑:2012年4月6日09:04 +02:00(中欧夏令时)
我设法在另一台硬件上测试我的应用程序,一台旧的iPhone 3G(iOS 4.2.1)。在旧的iPhone上,我的应用程序的行为与模拟器完全相同。在iPhone 4上运行相同的应用程序会产生不同的行为。
更准确地说:
- 在iPhone 4(iOS 5.1)上:应用程序正在执行我想要的操作,没有错误的行为。
- 在模拟器(iOS 5.1)上:应用程序在导航控制器的返回按钮上显示错误的标题。
- 在iPhone 3G(iOS 4.2.1)上:应用程序显示与模拟器中相同的错误行为。
编辑:2012年4月7日10:14 +02:00(中欧夏令时)
通过观察iPhone 3G上的过渡效果,我发现了一些有趣的、可能有用的东西:当我点击带有错误文本的按钮时,会发生以下情况:
- 错误文本被正确文本替换
- 在此替换后,视图以动画方式消失(向右滑动),下面的视图变得可见。这个转换持续大约0.3秒,在这个短时间间隔内,所有硬件-iPhone和模拟器中都可以看到正确的文本。
但问题仍然是:为什么iPhone 3G和模拟器显示错误的文本?为什么在iPhone 4中始终显示正确的文本?
对我来说,看起来好像在同一个位置有两个按钮,一个在另一个上面。在iPhone 4中,“我的”自定义按钮在前面,隐藏了旧的系统生成按钮,但在模拟器和iPhone 3G中,旧的系统生成按钮在前面,隐藏了我的自定义按钮。但是:即使我的隐藏自定义按钮比系统生成的按钮更大(更宽),也没有任何可见部分。只有在滑出动画开始时,我的按钮才变得可见。
编辑:2012年4月7日16:38 +02:00(中欧夏令时)
下一个有趣的事实:
到目前为止发生的情况如下:
当按钮第一次出现时(第二张截图,请参见下文),我将一个单词作为标题放在按钮上,该单词与系统之前生成的单词相同。然后用户选择某个操作,该按钮被另一个视图隐藏。在另一个用户操作之后,该按钮再次显示,现在它应该获得一个新的单词作为标题(意思相同,但是是新的语言),但是在iPhone 3G和模拟器上,旧标题更“强壮”。新标题不会显示。旧标题仍然存在。
如果我首先将一个与系统生成的标题不同的单词写成标题放在按钮上,则不会发生这种情况。如果第一个标题与默认标题不同,则稍后的更改将在所有iPhone和模拟器上执行。
这让我相信,iOS 进行了某种“优化”:如果在按钮首次出现时,自定义标题与系统生成的标题完全相同,则稍后更改按钮标题将被忽略,但仅适用于 iPhone 3G 和模拟器。在 iPhone 4 上,无论如何都可以允许稍后进行更改。但是,在一开始设置不同的标题以防止应用程序出现故障行为并不是一个选项。
parBackButton
、构建一个带有正确标题的新按钮并将其添加到视图的情况?我想知道这是否会有所不同。 - Cowirrie