Hub*_*ast 29 iphone ios ios-simulator
当导航控制器的后退按钮的标题发生变化时,在某些情况下旧标题会被卡住并且不会显示新标题.这仅在某些可重现的情况下发生,而在其他情况下则按其设计工作.
这取决于硬件
这取决于写入标题的单词
这取决于按钮在此期间是否不可见.
动画期间可以看到正确的标题
这是关于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(自动参考计数)正在使用中.
我确实定义了一个重绘协议:
Protocols.h
#ifndef ToDo_Project_Protocols_h
#define ToDo_Project_Protocols_h
@protocol redrawProt
- (void) mustRedraw;
@end
#endif
Run Code Online (Sandbox Code Playgroud)
这是表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
Run Code Online (Sandbox Code Playgroud)
其他Tables的头文件,SettingsTabVC.h并LangSelectTabVC.h定义相同的属性和相同的init函数
该计划从这里开始:
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
}
Run Code Online (Sandbox Code Playgroud)
接下来是表1(GeneralTableVC.m)的实现.表2(SettingsTabVC.m)和表3(LangSelectTabVC.m)中的代码类似地相同.我没有显示实现协议UITableViewDataSource的那些代码部分.我认为这些部分对解释问题并不重要.
在此代码中,您将找到与LocalizedString(keyword)完全相同的宏,即将NSLocalizedString(keyword,comment)关键字转换为所需的语言.我的这个宏的版本使用不同的bundel进行翻译(不是主要的包)
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
Run Code Online (Sandbox Code Playgroud)
在iPhone 5.1模拟器上启动应用程序将表1(GeneralTableVC)放在屏幕上:

在屏幕按钮的工具栏中,您可以在右侧找到设置按钮.按此按钮可在屏幕上显示下一个表格:

观看标题栏中的后退按钮.它显示文本"摘要",这是正确的,因为前一个表标题是"摘要".
现在我们选中第一行(" Language English >"):

一切都好.现在让我们改变语言.选项卡" German":

哇!现在一切都用德语.即使后退按钮已从"设置"更改为"Einstellungen".
让我们看看"Einstellungen"后退按钮:

现在差不多了; 一切都变成了德国人.除了后退按钮之外的所有内容,仍然显示"摘要"而不是"Überblick".我不明白为什么,因为当我在真正的iPhone 4上使用完全相同的源代码执行完全相同的步骤时,最后一个屏幕看起来像这样:

注意后退按钮上的文字.在真正的iPhone 4上,它是德语单词"Überblick"(这是我想要的),但在模拟器中它是英文单词"Summary".这对我来说意味着,在某些手机(如我的iPhone 4)上,用户可以获得预期的效果,但也许在其他手机(可能是iPhone 4S)上,用户会看到错误的显示器.
有谁知道我的代码有什么问题?
编辑次数: 2012-04-06 09:04 +02:00(欧洲中部夏令时间)
我确实设法在另一台硬件上测试我的应用程序,旧的iPhone 3G(iOS 4.2.1)在旧的iPhone上我的应用程序的行为与模拟器中的完全相同.在iPhone 4上运行相同的应用程序会产生不同的行为.
更确切地说:
编辑次数: 2012-04-07 10:14 +02:00(欧洲中部夏令时间)
通过观看iPhone 3G的过渡,我喜欢一些有趣的东西,也许是有用的:当我在按钮上选择错误的文字时,会发生以下情况:
但问题仍然是:为什么在iPhone 3G和模拟器中显示wront文本?为什么在iPhone 4中始终可以看到正确的文字?
对我而言,好像在同一个地方有两个按钮,一个在另一个上面.在iPhone 4中,"我的"自定义按钮位于前面,隐藏了旧的系统生成按钮,但在模拟器和iPhone 3G中,旧的系统生成按钮位于前面,隐藏了我的自定义按钮.但是:即使我隐藏的自定义按钮比系统生成的更大(更宽),也没有任何内容可见.仅当幻灯片动画开始时,我的按钮才会显示.
编辑次数: 2012-04-07 16:38 +02:00(欧洲中部夏令时间)
下一个有趣的事实
这就是现在发生的事情:
当按钮第一次出现时(第二次截图,见下文),我在其上添加了一个单词作为标题,这与系统之前的单词是一致的.然后用户选择一些动作,该按钮被另一个视图隐藏.在另一个用户操作后,按钮再次显示,现在它将获得一个新单词作为标题(相同的意思,但新语言),但在iPhone 3G和模拟器上旧标题"更强".新标题不会显示.旧标题贴在那里.
如果首先出现我在按钮上写一个单词作为标题,那就不会发生这种情况,这与系统生成的标题不同.如果第一个标题与默认标题不同,则稍后的更改将在所有iPhone和模拟器上执行.
这让我相信,iOS会做某种"优化":如果首次出现按钮,自定义标题与系统生成的标题相同,则稍后更改按钮标题将被忽略,但仅限于iPhone 3G和模拟器.在iPhone 4上,任何情况下都允许稍后更改.
但是在开头设置不同的标题以防止应用程序出现错误行为不是一种选择.
我就这个问题联系了 Apple 支持,他们确实给出了答复。
问题是,导航栏包含导航控制器堆栈上视图的所有后退按钮,并且所有这些按钮都需要同时更新。更新 viewWillAppear-Methods 中堆栈上的视图很好,但尝试在此位置更新后退按钮并不是一个好主意。
解决方案:
扩展UIViewController的接口:
@interface UIViewController (extended)
- (NSString *)localizedKey;
@end
Run Code Online (Sandbox Code Playgroud)
对于每个将视图放在 UINavigationController 堆栈上的 UIViewController 实现此方法:
- (NSString*) localizedKey {
return @"a title-keyword";
}
Run Code Online (Sandbox Code Playgroud)
不要乱用任何 UIViewControllerUIBarButtonItem或self.navigationItem.backBarButtonItem在任何 UIViewController 中乱搞。
当需要更改标题时,请使用以下代码片段对所有后退按钮执行此操作(记住:LocalizedString(key)是一个类似于 的自写宏NSLocalizedString(key,comment)):
NSArray* vcs = [self.navigationController viewControllers];
for (UIViewController* vc in vcs) {
vc.navigationItem.backBarButtonItem.title = LocalizedString([vc localizedKey]);
vc.title = LocalizedString([vc localizedKey]);
}
Run Code Online (Sandbox Code Playgroud)
Apple 支持的逐字答复:
我们正在与导航栏作斗争,以在错误的时间强制更新。请注意,每个视图控制器中的所有视图都已正确更新。所以导航栏需要特别注意才能得到我们想要的东西。
要使其正常工作,您需要立即将后退按钮更改为堆栈上的所有视图控制器(在用户选择语言时),而不是在它们通过“viewWillAppear”出现时更改。
这需要能够以公共方式获取该按钮的本地化密钥。我向 UIViewController 引入了一个类别,以便轻松采用:
@interface UIViewController (扩展)
- (NSString *)localizedKey;
@结尾然后您的 LangSelectTabVC 类可以立即更改所有后退按钮。这种方法将使按钮标题正确重绘。
因此在 viewWillAppear 中,您不必更新每个后退按钮。对于 UIKit 来说,这样做似乎为时已晚,无法赶上该更新。当更新发生时,您还可以重新创建一个新的后退按钮。这不是必需的,只需获取当前的并更改其标题即可:
NSArray *vcs = [self.navigationController viewControllers];
for (UIViewController *vc in vcs)
{
vc.navigationItem.backBarButtonItem.title = LocalizedString([vc localizedKey]);
vc.title = LocalizedString([vc localizedKey]);
}我附上了一个修改后的项目,显示了此解决方法。
| 归档时间: |
|
| 查看次数: |
2216 次 |
| 最近记录: |