近年のWebサイト開発では、かつてガラケーサイト開発がそうだったように、スマートフォン開発、タブレット開発が一般化してきました。「○○のような感じで」「○○のアプリにあるような」 こんな話しを要件定義の段階でよく耳にすることも増えました。スマートフォン開発では、画面をシンプルかつ、ユーザーにわかりやすい設計にすることが大事ですが、Webアプリを含め、多くのアプリが生まれた中で、ある程度ユーザーが認識してきた操作、というのもあります。左右のスワイプで、画像送りをしたり、画面上部でさらに下にひっぱることで、その画面全体の更新がかかる、など。 そうした意味でボタンの意味にも、共通の意識が芽生えてきました。その1つがメニューボタンです。
例えばこのようなボタンを見た時みなさんは、「メニューボタンだな」と認識できる人は多いのではないでしょうか。
「○○のような」という話しで言えば、「facebookアプリのような」メニューボタンです。
そして、このボタンをタップした時に、どのようにメニューが表示されるのか。
これも想像できる人は多いはずです。
先述のfacebookアプリでは、タップした時にメイン画面が右にスライドされるとともに、左からメニューがスライドしてきます。
Sencha Touch2.3.xでは、このようなメニューを簡単に実装できる機能が実装されました。
その名もExt.Menu
2.3.0がリリースされてからしばらくは、APIドキュメントにも記載されていなかったこの機能でしたが、
最近になって、記載されるようになりました。
使い方については、サンプルにあるKitchen Sink にExt.Menuのサンプルがあるので、
まずはこちらを見ていただくのが良いと思います。
Kitchen Sink ExampleのメニューにあるUserInterfaceから、さらに一番下にMenusがあるので、そこで確認ができます。
Ext.Viewport.toggleMenu(‘left’);
などで、メニューを切り替えることができます。
そのためには、Ext.Viewport.setMenu()により、メニューを定義する必要があります。
Ext.Menuでは、このようなスライドメニューを簡単に作成できるようになりました。
しかし、みなさんが作るアプリケーションは、こんなに単純ではないかもしれません。
例えば、スライドで表示した画面が、メニューボタンだけとは限りません。
次のようなコードで、右のスライドメニューの中に、xtype:datepickerfield
があったとしましょう。
Ext.define('MyApp.view.MyContainer', {
extend: 'Ext.Container',
alias: 'widget.my_container',
requires: [
'MyApp.view.MyTitleBar',
'Ext.Menu'
],
config: {
html: 'example',
items: [
{
xtype: 'mytitlebar'
}
]
},
initialize: function() {
this.callParent();
var me = this;
Ext.Viewport.setMenu(
Ext.create('Ext.Menu', {
width: 300,
items:[
{
xtype: 'button',
text: 'Close',
handler: function () {
Ext.Viewport.hideMenu('left');
}
}
]
}),
{
side: 'left',
reveal: true
}
);
Ext.Viewport.setMenu(
Ext.create('Ext.Menu', {
width: 300,
items: [
{
xtype: 'textfield',
label: 'text'
},
{
xtype: 'datepickerfield',
label: 'date'
}
]
}),
{
side: 'right',
reveal: true
}
);
}
});
すると、画面は下記のようになります。
ここに、datepickerfieldの箇所をタップすると、datepickerが現れるわけですが、、
このようにずれてしまいます。赤いしかくで囲った部分ですね。
こうなると、2つの対策を考えます。
- datepickerの位置を無理やりずらす
- Ext.Menuを諦める
datepickerの位置をずらす、という方法ですが、きっとやってできないことはないでしょうけど、
汎用性を考えると、ここはExt.Menuを使わずに、似たような動きをする作りにしてみます。
冗長な部分もあるかもしれませんが、あしからず・・・
まずは、app.js
Ext.application({
views: [
'Main',
'MyContainer',
'MyTitleBar',
'MyMenu'
],
name: 'MyApp',
launch: function() {
Ext.create('MyApp.view.Main', {fullscreen: true});
}
});
Main.jsは次のようにします。
Ext.define('MyApp.view.Main', {
extend: 'Ext.Container',
xtype: 'main',
requires: [
'MyApp.view.MyTitleBar',
'MyApp.view.MyMenu'
],
config: {
items: [
{xtype: 'my_container'},
{xtype: 'my_menu'}
]
}
});
xtype: ‘my_container’
はメインの表示となるものです。
Ext.define('MyApp.view.MyContainer', {
extend: 'Ext.Container',
alias: 'widget.my_container',
requires: [
'MyApp.view.MyTitleBar',
'MyApp.view.MyMenu'
],
config: {
html: '<div style="height:768px; background: #eee;">example</div>',
items: [
{
xtype: 'my_titlebar'
}
]
}
});
次にxtype: ‘my_menu’
。スライドして出てくる部分です。datepickerfieldだけつけてあります。
Ext.define('MyApp.view.MyMenu', {
extend: 'Ext.form.Panel',
alias: 'widget.my_menu',
config: {
width: '300px',
height: '100%',
hidden: true,
right: '0',
top: '0',
scrollable: false,
items: [
{
xtype: 'datepickerfield',
label: '日付',
name: 'Date',
labelWidth: '35%',
value: new Date(),
dateFormat: 'Y/m/d',
picker: {
slotOrder: ['year', 'month', 'day']
}
}
]
}
});
xtype: ‘my_titlebar’
は次のようにしました。
Ext.define('MyApp.view.MyTitleBar', {
extend: 'Ext.TitleBar',
alias: 'widget.my_titlebar',
config: {
docked: 'top',
title: 'MenuSample',
items: [
{
xtype: 'button',
align: 'right',
handler: function(button, e) {
var menu = Ext.Viewport.down('my_menu’),
container = Ext.Viewport.down('my_container');
if (menu.isHidden()) {
menu.setZIndex(-1);
container.setStyle({
'-webkit-transition-property': 'translate',
'-webkit-transition-duration': '0.3s',
'-webkit-transition-timing-function': 'linear'
});
menu.show();
container.translate(-300, 0);
Ext.defer(function () {
menu.setZIndex(0);
}, 300);
} else {
menu.setZIndex(-1);
container.translate(0, 0);
Ext.defer(function () {
menu.hide();
}, 300);
}
},
iconCls: 'settings'
}
]
}
});
注目すべきは、このMyTitleBar.jsにある、handlerの中です。
メニュー部分と、コンテナー部分をそれぞれ取得しています。
ここでは、タップされるたびに、コンテナーに対してsetStyleしてしまっていますが、
どこか初期化部分や、CSS自体に設定してしまっても良いと思います。
そのsetStyleの中身ですが、
'-webkit-transition-property': 'translate',
'-webkit-transition-duration': '0.3s',
'-webkit-transition-timing-function': 'linear'
こうすることで、Ext.Menuにあったような、スライドを表現することができます。
(実は、Ext.Menuも中をみると、同じようなことをやっています。)
ちなみにleftの値を少しずつずらす方法だと、重たすぎます。
その上で、
container.translate(-300, 0);
とすることで、300px分、コンテナー左にスライドします。
その直前にメニューをshowしておけば、その後ろにメニューが存在するように見えるというわけです。
スタイルなどは、全然調整していないので不格好ではありますが、
datepickerfieldをタップしても、ちゃんと、はみ出さず表示します。
Ext.Menuは便利なコンポーネントですが、適材適所で使っていきたいですね。