简而言之:
当导航控制器后退按钮的标题发生更改时,在某些情况下,旧标题会被卡住,而新标题将不会显示。这种情况仅发生在某些可重现的情况下,而在其他情况下它会按设计工作。
这取决于硬件
- 该错误发生在 iPhone 3G (iOS 4.2.1) 和模拟器 (iOS 5.1) 上
- 使用相同的源代码,iPhone 4 (iOS 5.1) 上没有错误
这取决于标题中写入的单词
- 创建按钮时,它从我自己编写的创建方法中获取与自动获取的标题相同的单词(即导航控制器堆栈上的上一页的标题),并且当其他情况匹配时,然后,当稍后尝试更改按钮的标题时,旧文本会卡住并且新标题将不会显示。
- 当在创建时按钮获得一个与其默认标题不同的单词作为标题时,只要您不为其分配默认标题,则其标题的每次更改都可以正常工作。
- 如果在对许多不同的标题进行多次成功更改之后,您将单词放在按钮标题上(这是其默认标题),那么该单词就会被卡住。以后的更改将不被接受(没有任何消息,并且只有在其他情况匹配的情况下)
这取决于按钮是否同时不可见。
- 如果另一个视图被推送到导航控制器堆栈上,则带有有缺陷按钮的旧页面会被新页面隐藏,并且当新页面稍后再次从堆栈中弹出时,这会使按钮再次可见,(并且当其他情况匹配)然后旧文本被卡住并且更改它的尝试被忽略(没有任何消息)。
- 如果该按钮是较新隐藏的,则更改其标题永远不会有问题。我总是工作。
动画期间可以看到正确的标题
- 当由于上述情况的组合而忽略更改后退按钮标题的尝试时,当按下后退按钮并且页面向右滑动的动画为时,正确的标题无论如何都会在大约 0.3 秒内可见。处理。在动画开始时,旧的卡住标题将被正确的标题替换,并且正确的标题在动画期间可见。
详细说明
这是关于a上的文字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)将被重新绘制,并且在几毫秒内屏幕上的所有文本都会以新语言显示。
重绘表格本身没有问题,导航栏中的标题也是如此。但后退按钮上的文字也必须翻译,这有点棘手。我对两个后退按钮都做了同样的技巧,对于表 3 上可见的指向表 2 的按钮来说效果很好。但是使用完全相同的代码,模拟器中存在问题(但在真实的设备上则不然) iPhone),表 2 上有按钮指向表 1。
我给您一些代码片段和一些屏幕截图,以向您展示我所做的事情以及正在发生的事情:
源代码
正在使用 ARC(自动引用计数)。
我确实定义了一个重绘协议:
协议.h
#ifndef ToDo_Project_Protocols_h
#define ToDo_Project_Protocols_h
@protocol redrawProt
- (void) mustRedraw;
@end
#endif
这是表 1 的标题:
通用表VC.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
and 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
}
接下来是表1的实现(GeneralTableVC.m
)。表2中的代码(SettingsTabVC.m
)和表3(LangSelectTabVC.m
) 类似地是相同的。我没有展示实现 UITableViewDataSource 协议的代码部分。我认为这些部分对于解释问题来说并不重要。
在此代码中,您将找到宏LocalizedString(keyword)
其作用与NSLocalizedString(keyword,comment)
,即将关键字翻译成所需的语言。我的这个宏版本使用不同的捆绑包进行翻译(不是主捆绑包)
通用表VC.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
) 在屏幕上:
在屏幕按钮的工具栏中,您可以在其右侧找到一个设置按钮。按下此按钮将在屏幕上显示下一个表格:
观察标题栏中的后退按钮。它显示文本“Summary”,这是正确的,因为上一个表标题是“Summary”。
现在我们用 Tab 键切换到第一行(“Language English >
"):
一切安好。
现在让我们更改语言。选项卡“German
":
哇!现在一切都是德语。甚至后退按钮也从“设置”更改为“Einstellungen”。
让我们点击“Einstellungen”后退按钮:
现在几乎一切都很好;一切都变成了德语。除了后退按钮之外的所有内容,该按钮仍然显示“Summary”而不是“Überblick”。我不明白为什么,因为当我在真正的 iPhone 4 上使用完全相同的源代码执行完全相同的步骤时,最后一个屏幕如下所示:
注意后退按钮上的文字。在真正的 iPhone 4 上,它是德语单词“Überblick”(这就是我想要的),但在模拟器中它是英语单词“Summary”。
这对我来说意味着,在某些手机(例如我的 iPhone 4)上,用户会得到预期的结果,但在其他一些手机(可能是 iPhone 4S)上,用户可能会遇到有问题的显示。
有人知道我的代码有什么问题吗?
EDITs
Edit:2012-04-06 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) 上:应用程序显示与模拟器中相同的错误行为。
Edit:2012-04-07 10:14 +02:00(中欧夏令时间)
通过观察 iPhone 3G 上的转换,我发现了一些有趣的事情,并且可能会有所帮助:当我点击带有错误文本的按钮时,会发生以下情况:
- 错误的文本被正确的文本替换
- 替换后,视图以动画方式消失(向右滑动),并且底层视图变得可见。此转换的持续时间约为 0.3 秒,在这段较短的时间内,所有硬件 iPhone 和模拟器中都可以看到正确的文本。
但问题仍然是:为什么iPhone 3G和模拟器中显示错误的文字?为什么在 iPhone 4 中总是可以看到正确的文本?
在我看来,好像同一个地方有两个按钮,一个在另一个上。在 iPhone 4 中,“我的”自定义按钮位于前面,隐藏了旧的系统生成的按钮,但在模拟器和 iPhone 3G 中,旧的系统生成的按钮位于前面,隐藏了我的自定义按钮。但是:即使我隐藏的自定义按钮比系统生成的更大(更宽),也看不到任何内容。仅当滑出动画开始时,我的按钮才可见。
Edit:2012-04-07 16:38 +02:00(中欧夏令时间)
下一个有趣的事实:
这是到目前为止发生的事情:
当该按钮第一次出现时(第二张屏幕截图,见下文),我在其上放置了一个单词作为标题,该单词与系统之前生成的单词相同。然后用户选择某个操作,并且该按钮被另一个视图隐藏。在另一次用户操作之后,按钮再次显示,现在它应该得到一个新词作为标题(含义相同,但新语言),但在 iPhone 3G 和模拟器上,旧标题“更强”。新标题将不会显示。旧标题仍保留在那里。
如果第一次出现时我在按钮上写了一个与系统生成的标题不同的单词作为标题,则不会发生这种情况。如果第一个标题与默认标题不同,则稍后的更改将在所有 iPhone 和模拟器上执行。
这让我相信,iOS 做了某种“优化”:如果按钮第一次出现时,自定义标题与系统生成的标题相同,则按钮标题的后续更改将被忽略,但仅限于 iPhone 3G和模拟器。在 iPhone 4 上,无论如何都允许稍后进行更改。
但在开始时设置不同的标题来防止应用程序出现错误行为并不是一种选择。