[Titanium勉強日記 2] 画面遷移してみる

HelloWorldができたので次は画面遷移をしたいですね。それで適当にググりながら下記の様なコードを書いてみたのですが上手く動きません。アニメーションされずにパッと画面が切り替わってしまいます。

// 実験1
var win = Ti.UI.createWindow({backgroundColor: 'blue'});
var btn = Ti.UI.createButton({title: 'push to open'});
btn.addEventListener('click', function() {
	var win2 = Ti.UI.createWindow({backgroundColor: 'red'});
	win2.open({animated: true});
});
win.add(btn);
win.open();

そこでwin2.openを呼び出す際のプロパティを下記のように変更すると、iPhoneの時のみアニメーションするようになりましたが、それでは駄目です。何の為にTitanium使うと思ってるんですか。Androidでも普通のアニメーションしながら画面遷移くらいしてくれと思いますよね。

// 実験2
var win = Ti.UI.createWindow({backgroundColor: 'blue'});
var btn = Ti.UI.createButton({title: 'push to open'});
btn.addEventListener('click', function() {
	var win2 = Ti.UI.createWindow({backgroundColor: 'red'});
	win2.open({transition: Titanium.UI.iPhone.AnimationStyle.CURL_DOWN});
});
win.add(btn);
win.open();

その後、色々試行錯誤して結局以下のように書き換えて上手くいきました。シングルウィンドウのアプリでもTabGroupを使えば良いようです。その代わりにtabBarHiddenを指定します。これでiPhoneの場合はUINavigationControllerにpushした時の挙動を示します。Androidでもデフォルトのアニメーションが動きますし、遷移先からバックボタンで元の画面に戻れます。

// 実験3
var tabGroup = Titanium.UI.createTabGroup();

var win = Titanium.UI.createWindow({  
    title:'Tab 1',
    backgroundColor:'blue',
	tabBarHidden: true,
});
var tab = Titanium.UI.createTab({  
    title: 'Tab 1',
    window: win
});

var btn = Ti.UI.createButton({title: 'push to open'});
btn.addEventListener('click', function() {
	console.log('click');
	var child = Ti.UI.createWindow({title:'child', backgroundColor: 'red'});
	tab.open(child, {animated:true});
});
win.add(btn);

tabGroup.addTab(tab);
tabGroup.open();

ただ問題は残っていて、Androidの方でtabBarHiddenが動作せず、タブが1つ表示されてしまって微妙です。なんとかならないのと調べてみると、公式フォーラムに解答がありました。

まず(app-project-dir)/platform/android/res/layout/というディレクトリを作成して、その中にtitanium_tabgroup.xmlというファイル名で下記を追加すればタブバーを消す事ができます。

<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/tabhost"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
 
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:padding="0dp">
 
        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:padding="0dp"
            android:layout_weight="1"/>
 
        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="0"/>
 
    </LinearLayout>
	
</TabHost>

以上で、最初にやりたいなと思っていた挙動は実現できたのですが、まだ釈然としない事がありました。それはopenを呼ぶ際に指定できるオプションがドキュメントを見ても良く解らなかった事です。一番最初のコードではanimatedが動作しませんが、最後のコードではanimatedが動作します。でも理由が分からないのです。Titanium BBSで質問してみたところ、そういうものだという事なので、やはりある程度ソースコードを確認する必要があるようです。

プロジェクトルート直下のbuildディレクトリにiPhoneの場合はxcodeprojが生成されています。デバッグ実行も可能なので適当にソースコードを追ってみたところ、TiWindowProxy.mのopenが下記のようになっていて、openに渡したargsをそのままTiAnimation::animationFromArgの呼び出しに使っています。

-(void)open:(id)args
{
	if ([[[[TiApp app] controller] modalViewController] isKindOfClass:[TiErrorController class]]) { // we have an error dialog up
		return;
	}
	// opening a window more than once does nothing
	if (opened==YES)
	{
		return;
	}

	[self rememberSelf];
	
	//First, we need to get our arguments in order. Perhaps in Opening.

	if (opening==NO)
	{
		modalFlag = [self isModal:args];
		fullscreenFlag = [self isFullscreen:args];
		if (!modalFlag)
		{
			[self forgetProxy:openAnimation];
			RELEASE_TO_NIL(openAnimation);
			openAnimation = [[TiAnimation animationFromArg:args context:[self pageContext] create:NO] retain];
			[self rememberProxy:openAnimation];
		}
		opening = YES;
	}
    TiThreadPerformOnMainThread(^{
        [self openOnUIThread:args];
    }, YES);
}

そしてTiAnimation::animationFromArgの内容が以下です。animatedが指定されている場合は、同時にanimationStyleが指定されない限りアニメーションが行われないようになっています。最初のコードでアニメーションが動かない理由が分かりましたね。

+(TiAnimation*)animationFromArg:(id)args context:(id<TiEvaluator>)context create:(BOOL)yn
{
	id arg = nil;
	BOOL isArray = NO;
	
	if ([args isKindOfClass:[TiAnimation class]])
	{
		return (TiAnimation*)args;
	}
	else if ([args isKindOfClass:[NSArray class]])
	{
		isArray = YES;
		arg = [args objectAtIndex:0];
		if ([arg isKindOfClass:[TiAnimation class]])
		{
			return (TiAnimation*)arg;
		}
	}
	else 
	{
		arg = args;
	}

	if ([arg isKindOfClass:[NSDictionary class]])
	{
		NSDictionary *properties = arg;
		KrollCallback *cb = nil;
		
		if (isArray && [args count] > 1)
		{
			cb = [args objectAtIndex:1];
			ENSURE_TYPE(cb,KrollCallback);
		}
		
		// old school animated type properties
		if ([TiUtils boolValue:@"animated" properties:properties def:NO])
		{
			float duration = [TiUtils floatValue:@"animationDuration" properties:properties def:1000];
			UIViewAnimationTransition transition = [TiUtils intValue:@"animationStyle" properties:properties def:UIViewAnimationTransitionNone];
			TiAnimation *animation = [[[TiAnimation alloc] initWithDictionary:properties context:context callback:cb] autorelease];
			animation.duration = [NSNumber numberWithFloat:duration];
			animation.transition = [NSNumber numberWithInt:transition];
			return animation;
		}
		
		return [[[TiAnimation alloc] initWithDictionary:properties context:context callback:cb] autorelease];
	}
	
	if (yn)
	{
		return [[[TiAnimation alloc] _initWithPageContext:context] autorelease];
	}
	return nil;
}

animatedが指定されない場合は、更にargをTiAnimation::initWithDictionaryに引き渡しています。TiAnimationはtransitionプロパティを持っていて、このイニシャライザで渡ってきたプロパティをセットしています。これで2つ目のtransitionが動いた理由も分かりました。同様にTiUITabProxy.mのopenOnUIThreadを確認すると、animatedをUINavigationController::pushViewControllerに渡している事が分かります。

というわけで同じopenというメソッドでもクラスによって指定できるオプションは違うし、同じ名前のオプションを指定したとしても内部での使われ方が違います。つまり完全にTitaniumをブラックボックスと捉えると、想定される挙動が得られない事があると言う事です。

どこかでTitaniumは独自のAPIを揃えているのでCocoaやAndroid SDKの知識はいらないよ、TitaniumのAPI覚えるだけで良いよ、と言った記述を見たのですが、それは正しいとは言えない気がします。恐らくObjective-CやJavaのコードと行ったり来たりする事になりそうで、思ったよりは大変そうですね。それでもObjective-CやJava単体でコード書くのに比べると格段に楽だとは思いますけども。

そんなわけでアプリ書き始めようと思います。

3 thoughts on “[Titanium勉強日記 2] 画面遷移してみる”

  1. Предлагаем полностью рабочее программное обеспечение/We offer cracked PLAXIS 3D 2015 ALL MODULES (CRACK – Dongle emulator/Custom license/Patch). Полная поддержка наших решений. Тестирование перед оплатой/Full support for our solutions. Testing before payment. Контакты/Contacts: nodongle24 /@/ gmail.com (remove spaces and /)

    Hasp H4 Dongle Emulator, Guardant Stealth III Dongle Emulator, Matrixhid Dongle Emulator, P-Sea Aka Unikey Dongle Emulator, Smartkey Eutron Usb Dongle Emulator, FLEXlm License Manager, Hasp Hl Dongle Emulator, buy, Smartlock Dongle Emulator, Hardlock Dongle Emulator, Marx CrypToken Dongle Emulator, Sparkey Dongle Emulator, кряк, Marx CrypToken Dongle Emulator, Sentinel Scout Dongle Emulator.

  2. http://www.cars-blogi.com.pl/specjalny-mechanizm-gasienicowy-pojazdu-arktycznego
    Shopping for a new or used vehicle could be a hard method unless you know what you will be undertaking. By teaching yourself about auto shopping before you head to the car dealership, you possibly can make issues easier on your own. The following advice may help your upcoming purchasing trip be pleasurable.

    Usually take a auto technician alongside when searching for a fresh car. Auto sellers are notorious for promoting lemons and you may not want to be their following patient. Whenever you can not have a auto technician to check out vehicles along with you, at the very least make certain you have him take a look at final option before buying it.

    Know your limits. Before you start buying for your forthcoming automobile or vehicle, decide how much you can manage to spend, and follow it. Don’t neglect to feature desire for your estimations. You can expect to spend about 20 percent as a payment in advance as well, so prepare yourself.

    Before going to a dealership, know which kind of motor vehicle you desire. Research most of you alternatives before purchasing to help you determine what works well with your financial allowance and household requires. Do your research to learn just how much you must pay for a probable auto.

    Prior to signing any contract make time to read through each series, such as the small print. If there is something detailed that you simply do not fully grasp, usually do not signal until you receive an respond to that you just fully grasp. Unsavory salesmen can make use of a binding agreement to put many fees which were not discussed.

    If you keep your preceding advice in mind when that you simply go looking for a car, you will end up very likely to obtain a good package. Buying a automobile lacks as a headache. Only use the information with this article and you may receive the car you desire with a good selling price.

  3. Есть такая услуга – добровольное медицинское обслуживание .
    Она предполагает, что пациент вносит небольшую сумму за то, что посещает врачей весь год не платя за каждый прием.
    Однако опросы показали, что лишь 3% жителей города знают о ее существовании.
    По какой причине?
    Да потому что частным клиникам выгоднее брать плату за каждое посещение.
    А если честный врач попытается рассказать про добровольное медицинское обслуживание клиенту – это сулит ему увольнением.
    Эта информация уже вызвала множество возмущений, сразу после того как информацию об этом рассекретил один возмущенный врач.
    Его уволили , после того, как он посоветовал ДМО постоянному клиенту.
    Самое ужасное, что официальные положения по ДМО присутствуют в открытом доступе, просто находили на эту информацию единицы.
    Как отстоять свои права?
    О правилах предоставления такой услуги и обязанностях клиник можно узнать, сделав запрос в Яндексе: “добровольное медицинское обслуживание”.
    И именно обслуживание, а не страхование.

    34j5c6h86

Leave a Reply

Your email address will not be published. Required fields are marked *