テーマを設定する
続いて、テーマの設定方法を解説します。前述の通り、Material Designはテーマカラーを設定することでオリジナリティのあるデザインを生み出すことができます。試しに、CodeZineのカラーリングを参考にして、テーマを作ってみましょう。
Material Designの色システムでは、19種類のベースカラーが用意されており、それの濃淡を数値で表現します。探してみると、CodeZineのメインカラーと近いのはLightBlueの800番、アクセントカラーと近いのはTealの200番でした(図7)。
それでは、これをテーマの形に落とし込んでみましょう。リスト3はテーマを適用する実装です。
import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import lightBlue from '@material-ui/core/colors/lightBlue';
import teal from '@material-ui/core/colors/teal';
import AppBar from '@material-ui/core/AppBar';
import Button from '@material-ui/core/Button';
import Container from '@material-ui/core/Container';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
const theme = createMuiTheme({ // (1)
palette: {
primary: {
main: lightBlue[800], // (3)
},
secondary: {
main: teal[200], // (4)
}
},
});
function App() {
return (
<ThemeProvider theme={theme}>{/* (2) */}
<AppBar position="static" color="primary">{/* (5) */}
<Toolbar>
<Typography variant="h6">サンプル</Typography>
</Toolbar>
</AppBar>
<Container>
<Button variant="contained" color="secondary">{/* (6) */}
Hello World
</Button>
</Container>
</ThemeProvider>
);
}
export default App;
テーマは(1)のようにcreateMuiTheme関数で作成します。作成したtheme変数を(2)のように<ThemeProvider>コンポーネントに渡して、他のMaterial-UIのコンポーネントを包むことで、テーマを適用します。色は(3)と(4)のように設定しています。
今回は(5)で<AppBar>(ヘッダー)を使ってみました(後編で解説します)。こちらは色をprimaryに設定したので、`lightBlue[800]の色になります。また、ボタンの色はsecondaryに設定したので、teal[200]^^の色になります。それでは実際にどうなったか見てみましょう(図8)。
それらしい色になりました。このように、テーマで色を指定することで、統一感のあるUIを容易に構築できます。
Boxの例
それでは、もう少し実例を見てみましょう。Boxコンポーネントで領域を区切って、簡単なレイアウトを組んでみます(リスト4)。
// 略
import Box from '@material-ui/core/Box';
function App() {
return (
{/* (略) */}
<Container>
<Box style={{ display: 'flex', flexDirection: 'row' }}>{/* (1) */}
<Box width={1/4} style={{ padding: '8px' }} border={1}>{/* (2) */}
<Button
variant="contained"
color="secondary"
style={{ width: '100%' }}
>
ボタン1
</Button>
</Box>
<Box width={1/2} style={{ padding: '8px' }} border={1}>{/* (3) */}
<Button
variant="contained"
color="secondary"
style={{ width: '100%' }}
>
ボタン2
</Button>
</Box>
<Box width={1/4} style={{ padding: '8px' }} border={1}>{/* (2) */}
<Button
variant="contained"
color="secondary"
style={{ width: '100%' }}
>
ボタン3
</Button>
</Box>
</Box>
</Container>
{/* (略) */}
);
}
export default App;
まずは(1)で横方向のFlexboxを定義します。そして、 widthの値を1/4にした(2)と、1/2にした(3)を並べてみました。直感的には1:2:1の比になりそうな指定ですね。実際に動かしてみると、表示は図9のようになります。
1:2:1の比になりました。Boxをはじめとしたレイアウトに関するコンポーネントでは、widthやheightに割合を指定でき、親(ここでは(1)のBox)の幅に対して割合に応じた幅を持つことができます。
Menuの例
最後に、ナビゲーションのジャンルから、Menuコンポーネントの例を挙げてみます。ボタンを押すとメニューが開いて、選択すると閉じる、という簡単なものです(リスト5)。
function MenuSample() {
const [anchorEl, setAnchorEl] = useState(null);
const handleClick = (event) => {
setAnchorEl(event.currentTarget); // (4)
};
const handleClose = () => {
setAnchorEl(null); // (5)
};
return (
<Box>
<Button
variant="contained"
color="secondary"
onClick={handleClick}
>
メニューを開く
</Button>
<Menu // (2)
id="simple-menu"
anchorEl={anchorEl} // (1)
open={Boolean(anchorEl)} // (3)
onClose={handleClose}
>
<MenuItem onClick={handleClose}>アイテム1</MenuItem>
<MenuItem onClick={handleClose}>アイテム2</MenuItem>
<MenuItem onClick={handleClose}>アイテム3</MenuItem>
</Menu>
</Box>
);
}
Menuコンポーネントの表示位置は(1)でanchorEl属性に設定したDOM要素からの相対位置で決定されます。そのため、JSX内ではどこに記述しても構いませんが、管理上の扱いやすさから、anchorElに設定する要素から近い場所に記述する慣例があります。今回の例では、(2)のようにButtonの真下に記述しました。
(3)のopen属性にtrueを与えると、メニューが表示されます。ボタンのクリック時に(4)のように取得した要素を、(3)で真偽値に変換してからopen属性に渡すことで「ボタンクリックでメニューを表示」という挙動を実現しています。逆に閉じるときは、MenuItemやメニュー外をクリックした際に呼び出されるhandleClose関数内で(5)の処理をすることで、(3)に渡る値をfalseにしています。なお、開閉状態の管理と要素の管理は別々に行っても問題ありません。
まとめ
今回はMaterial-UIの解説の前編でした。Webサイトやアプリを組み上げていくために必要な部品が初めからそろっている中で開発するのは楽しいですね。次回は引き続き、Material-UIについて解説します。
