RE:ADV

UnityでADVを作るブログ

MarkLightの使い方を再学習するときに参照するまとめ

MarkLightとは?

UnityのUIをXUMLと呼ばれるマークアップLで記述できるアセット。
20161218現在 20$
www.marklightforunity.com


去年はMarkUXという名前でした。
UniRxとの繋ぎこみの話。
ykimisaki.hatenablog.jp


Documentation->Tutorialsオーバービュー

Examples and How To'sをちらっと
パラメータをエディタから探したいので、インテリセンスほしくなりますよね。

How to Get Intellisense in XUML

VisualStudioのスキーマフォルダにプロジェクト内にある.xsdファイルのアドレスを書き込む。
管理者権限でテキストエディタを開いて編集。

C:\Program Files (x86)\Microsoft Visual Studio 14.0\Xml\Schemas

<Schema targetNamespace="MarkLight" href="C://Assets/MarkLight/Views/Schemas/MarkLight.xsd"/>
を書き込む。
つくったViewのxmlのルートを
<YourView xmlns="MarkLight">
こんな感じで


Getting Started

UIを作成する流れ
Sceneに空のGameObjectを作成->View Presenterをアタッチ
Viewファイル作成->using MarkLight.Views.UI して UIViewを継承
ViewModel(Viewと同名.cs)作成->
ViewのルートになるViewを作成->
ViewModel作成->using MarkLight して Viewを継承
View Presenter のインスペクターから ルートのViewを参照
スタイルをあてる

以下見出し的に紹介
View Action : イベントを指定したタグと結びつけられた名前のメソッドを呼び出す機能
Layout : タグで切り出されたコンテンツを並べてレイアウトする機能
ViewSwitcher : タグで切り出されたコンテンツを入れ替える機能
データバインディング : フィールドの値との TwoWay バインディングサポート
Animations : View上で名前で紐づけるアニメーション
SetValue() : UIの値を指定して変化させる
DependencyFields : SetValue()のエイリアス記法


View Models - Bringing Views to Life

クラス名<-->タグ名
フィールド名<-->パラメータ で紐づけ

SetValueメソッドで値を変更
型名の前に_をつけて宣言->ディペンダンシーフィールド
.Value で内部の値にアクセス(オブザーバーが効いてノティファイする)
.DirectValue で内部の値にアクセス(オブザーバーがスルーしてノティファイしない)

UIの子要素を宣言<-->タグ名
子要素UIの名前<-->Idパラメータ で紐づけ

もしくは <タグ名:クラス名 UI.フィールド="値"> の記法でダイレクト参照可

ViewAction型 UnityEvent(or カスタムメソッド名)
<クラス名 ViewActionの名前="値"> で紐づけ
メソッド名.Trigger()
メソッド名.Trigger(data) でインボーク

Textコンポーネントに紐づいた内部stringをディペンダンシーフィールドで表現
[Mapto("Textコンポーネントの名前.Text")]
public _string アクセス用の名前;
こう宣言するとUI.Text.Textにアクセス用の名前.Valueもしくはアクセス用の名前="値"でアクセスできる。

ChangeHandlerアトリビュートでフィールドが変更されたら呼び出すメソッドを定義できる。
MapToアトリビュートの第二パラメータで設定してもよい。
値のイニシャライズ専用の記法・メソッドがあるよ


データバインディング

記法は
ターゲットフィールド="{ソースフィールド}"
ソースフィールドをSetValueメソッド等で入れ替えると、自動的にターゲットフィールドが書き換わる。

ソースフィールドをディペンダンシーフィールドで定義すると(_stringのように型に_をつけて宣言)フィールド.Value=値 のように代入でSetValueと同じことができる
ネストしたパスに対して . でアクセスできる
フォーマットストリングバインディングやマルチフィールドバインディングをサポート
"{=ソースフィールド}"でワンウェイバインディング
"{#ソースフィールド}"でローカルバインディング

ListItemバインディング

<BindingExample>
  <List Items="{HighScores}">
    <ListItem IsTemplate="True" Text="{#Item.Score}" />
  </List>
</BindingExample>

この例でListは、 ローカルバインディングされたアイテムのScoreフィールドを持つ ListItem を複数個保持する HighScoresオブジェクトをバインドしている。

ブーリアンのフィールドとバインディングした場合
IsChecked="{!ShieldActive}"
と値を反転して保持することができる

Resourceバインディング
ディクショナリーに対して、
"{@ディクショナリ名.キー}"もしくは"{@キー}"でバインディングできる

最後にバインディングチートシートがついてます。
こんな例も

<Label Text="{!=#IsActive}" />

Negated One-way Local!


テーマとスタイルの作成

Themaタグ内で名前を指定してつくる
Thema内でstyleやidを指定しておくと使うときに適用された状態で呼び出せる
BasedOn=""でスタイルの上書きができる
見た目だけじゃなくふるまいを設定することもできる
テーマをひとつのシーン・ビューにいくつも読み込むことができる
Style="*"と書くと親のスタイルをインヘリト(継承)する


Working with List Data

List,DataGrid,ComboBox,TabPanelはリストに関係している。ひとまず基礎的なリストについて
Staticなリストはタグで簡単に作れる
Dynamicなリストは...
まず以下のモデルクラスを考えてみる
Highscore.cs

public class Highscore
{
    public string Player;
    public int Score;
}

自動変更通知リストとしてObservableListを使う

上のモデルを含んだリストを見てみよう
DynamicListExample.cs

public class DynamicListExample : UIView
{
	public ObservableList<Highscore> Highscores;

	public override void Initialize()
	{
		Highscores = new ObservableList<Highscore>();
		Highscores.Add(new Highscore { Player = "PlayerA", Score = 100 });
		Highscores.Add(new Highscore { Player = "PlayerB", Score = 750 });
		Highscores.Add(new Highscore { Player = "PlayerC", Score = 9000 });
		Highscores.Add(new Highscore { Player = "PlayerD", Score = 9000 });
	}
}

Viewにバインドする
DynamicListExample.xml

<DynamicListExample>
	<List Items="{Highscores}" Width="200">
		<ListItem IsTemplate="True" Text="{#Item.Player} {#Item.Score}" />
	</List>
</DynamicListExample>

三つの重要なポイントがある

  • <List Items="{Highscores}" /> オブザーバブルリストとバインドしたリストを宣言
  • <ListItem IsTemplate="True" ... /> テンプレートを使うことを宣言
  • <ListItem IsTemplate="True" Text="{#Item.Player} {#Item.Score}" />  最後にitem template とItemDataをバインドする

見た目を整える
DynamicListExample.xml

<DynamicListExample>
	<List Items="{Highscores}" width="250">
		<ListItem IsTemplate="True">
			<Region Margin="10">
				<Label Text="{#Item.Player}" Alignment="Left" FontColor="Black" FontSize="22" AdjustToText="Width"></Label>
				<Label Text="{#Item.Score}" Alignment="Right" FontColor="Black" AdjustToText="Widht"></Label>
			</Region>
		</ListItem>
	</List>
</DynamicListExample>

xmlを書くときにEMMETを使ったので備忘
上のxmlをつくるときはCustom attribute の記法を使う

td[rowspan=2 colspan=3 title]
<td rowspan="2" colspan="3" title=""></td>
DynamicListExample>List[Items={Highscores} width=250]>ListItem[IsTemplate=True]>Region[Margin=10]>Label[Text={#Item.Player} Alignment=Left FontColor=Black FontSize=22 AdjustToText=Width]+Label[Text={#Item.Score} Alignment=Right FontColor=Black AdjustToText=Widht]

以上を打ち込んで Ctrl + E(VScodeの場合はTAB)

itemの追加と削除

//インデックスによる削除
Highscores.RemoveAt(0);
//リファレンスによる削除
var item = Highscores.Find(x => x.Player == "PlayerB");
Highscores.Remove(item);
//itemの追加
Highscores.Add(new Highscore { Player = "Player", Score = 0 });
//インデックスによる追加
Highscores.Insert(0, new Highscore { Player = "Player", Score = 0 });

itemのアップデート(変更通知)
例えば、最高得点が更新されました、といったシナリオ

//Update Items
public void UpdateScores()
{
	//scenario#1 - アイテムによってプレイヤー名を更新する
	var item = Highscores[0];
	item.Player = "New Name";
	Highscores.ItemModified(item, "Player");

	//senario#4 - すべてのリストアイテムのすべてのフィールドを更新
	Highscores.ItemModified();
}

ひとまず備忘録として残します