$30 off During Our Annual Pro Sale. View Details »

TabBarの色を変えたかっただけなのに

 TabBarの色を変えたかっただけなのに

Flutter Meetup Tokyo #15

FlutterのTabBarの背景色を変たい、と思ったらMaterialやInkの話、そしてTabBarのIndicatorの話まで広がりました。

スライドの最後に紹介しているリンクをこちらにも貼っておきます。
https://qiita.com/mkosuke/items/3e33d71ef4de74364f87
https://qiita.com/mkosuke/items/e506256515179d0f421b

kosuke matsumura

March 18, 2021
Tweet

More Decks by kosuke matsumura

Other Decks in Technology

Transcript

  1. TabBarͷ৭Λม͔͚͑ͨͬͨͩͳͷʹ Flutter Meetup Tokyo #15 2021/3/18 Kosuke Matsumura

  2. About Me • দଜߤ༟(Kosuke Matsumura) • NAVITIME JAPAN Co., Ltd.

    
 ɹAndroid / iOS • JϦʔά(઒࡚ϑϩϯλʔϨ)αϙʔλʔ • Twitter 
 m.kosuke @kosuke_mtm ɾϓϩμΫτ͕ଟ༷͘ʑͳαʔϏεΛܦݧͰ͖Δʂ ɾ৽نΞϓϦ্ཱͪ͛΍ϦχϡʔΞϧʹࢀըͰ͖Δνϟϯε͕ଟ͍
  3. About Me • ݸਓͰΞϓϦ΋ϦϦʔε͍ͯ͠·͢

  4. TabBarͷ৭Λ ม͔͚͑ͨͬͨͩͳͷʹ

  5. TabBarͷഎܠ৭Λ ม͔͚͑ͨͬͨͩͳͷʹ ͜ΕΛ͜͏ʂ

  6. جຊతͳTabBar @override Widget build(BuildContext context) { return DefaultTabController( length: 2,

    child: Scaffold( appBar: AppBar( title: Text('AppBar'), bottom: TabBar( tabs: [ Tab(child: Text('Tab A')), Tab(child: Text('Tab B')), ], ), ), body: TabBarView( children: [ Page1(), Page2(), ], ), ), ); } "QQ#BS 5BC#BS 5BC#BS7JFX
  7. جຊతͳTabBar @override Widget build(BuildContext context) { return DefaultTabController( length: 2,

    child: Scaffold( appBar: AppBar( title: Text('AppBar'), bottom: TabBar( tabs: [ Tab(child: Text('Tab A')), Tab(child: Text('Tab B')), ], ), ), body: TabBarView( children: [ Page1(), Page2(), ], ), ), ); } "QQ#BS 5BC#BS 5BC#BS7JFX
  8. جຊతͳTabBar @override Widget build(BuildContext context) { return DefaultTabController( length: 2,

    child: Scaffold( appBar: AppBar( title: Text('AppBar'), bottom: TabBar( tabs: [ Tab(child: Text('Tab A')), Tab(child: Text('Tab B')), ], ), ), body: TabBarView( children: [ Page1(), Page2(), ], ), ), ); } "QQ#BS 5BC#BS 5BC#BS7JFX
  9. جຊతͳTabBar @override Widget build(BuildContext context) { return DefaultTabController( length: 2,

    child: Scaffold( appBar: AppBar( title: Text('AppBar'), bottom: TabBar( tabs: [ Tab(child: Text('Tab A')), Tab(child: Text('Tab B')), ], ), ), body: TabBarView( children: [ Page1(), Page2(), ], ), ), ); } "QQ#BS 5BC#BS 5BC#BS7JFX
  10. جຊతͳTabBar @override Widget build(BuildContext context) { return DefaultTabController( length: 2,

    child: Scaffold( appBar: AppBar( title: Text('AppBar'), bottom: TabBar( tabs: [ Tab(child: Text('Tab A')), Tab(child: Text('Tab B')), ], ), ), body: TabBarView( children: [ Page1(), Page2(), ], ), ), ); } "QQ#BS 5BC#BS QSJNBSZ$PMPS JOEJDBUPS$PMPS
  11. جຊతͳTabBar "QQ#BS 5BC#BS QSJNBSZ$PMPS .BUFSJBM%FTJHOͷඪ४Ͱ͸ "QQ#BSͱ5BC#BSͷ৭͸ಉҰɻ ʢม͑ͯ͸μϝͱ͸ॻ͍͍ͯͳ͍ʣ IUUQTNBUFSJBMJPDPNQPOFOUTUBCTVTBHF "QQ#BSͱ5BC#BSͷഎܠ৭ ͸QSJNBSZ$PMPSͰಉҰ

  12. جຊతͳTabBar "QQ#BS 5BC#BS QSJNBSZ$PMPS 5BC#BSʹഎܠ৭Λઃఆ͢Δ*'͸ͳ͍ const TabBar({ Key key, @required

    this.tabs, this.controller, this.isScrollable = false, this.indicatorColor, this.indicatorWeight = 2.0, this.indicatorPadding = EdgeInsets.zero, this.indicator, this.indicatorSize, this.labelColor, this.labelStyle, this.labelPadding, this.unselectedLabelColor, this.unselectedLabelStyle, this.dragStartBehavior = DragStartBehavior.s this.mouseCursor, this.onTap, this.physics, }) 5BC#BSͷ৭Λม͍͑ͨʂ ͱ͍͏ͷ͕ࠓճͷओ୊Ͱ͢ɻ
  13. TabBarͷഎܠ৭Λม͍͑ͨ $PMPSFE#PYͳͲΛ5BC#BSͷԼʹෑ͘ DefaultTabController( length: 2, child: Scaffold( appBar: AppBar( title:

    Text('Title'), bottom: PreferredSize( preferredSize: Size.fromHeight(72), child: ColoredBox( color: Colors.redAccent, child: TabBar( tabs: [ Tab(child: Text('Tab A')), Tab(child: Text('Tab B')), ], ), ), ), ), body: TabBarView( children: [ Page1(), Page2(), ], ), ), $PMPSFE#PYͰ5BC#BSΛғΊ͹0,ʂ
  14. TabBarͷഎܠ৭Λม͍͑ͨ $PMPSFE#PYͳͲΛ5BC#BSͷԼʹෑ͘ DefaultTabController( length: 2, child: Scaffold( appBar: AppBar( title:

    Text('Title'), bottom: PreferredSize( preferredSize: Size.fromHeight(72), child: ColoredBox( color: Colors.redAccent, child: TabBar( tabs: [ Tab(child: Text('Tab A')), Tab(child: Text('Tab B')), ], ), ), ), ), body: TabBarView( children: [ Page1(), Page2(), ], ), ), 3JQQMF& ff FDU͕ දࣔ͞Εͳ͍
  15. Ripple Effect͸ʮഎܠʯ "QQ#BS 5BC#BS

  16. Ripple Effect͸ʮഎܠʯ 3JQQMF& ff FDU͸*OL8FMM΢ΟδΣοτͷද໘Ͱ͸ͳ͘ɺ എܠͱͯ͠.BUFSJBMͷ্Ͱඳը͞ΕΔ "QQ#BS .BUFSJBM 5BC#BS *OL8FMM

    ɹ*OL8FMM͕λονΠϕϯτΛݕ஌ ɹ3JQQMF& ff FDU͸ 
 ɹ.BUFSJBM΢ΟδΣοτ্Ͱඳը͞ΕΔ
  17. Ripple Effect͸ʮഎܠʯ ʲ.BUFSJBMͷ্ʹෆಁ໌ͳ8JEHFU͕͋Δ৔߹ʳ "QQ#BS .BUFSJBM 5BC#BS *OL8FMM ɹ$PMPSFE#PY͕अຐͰ3JQQMF& ff FDU͕ݟ͑ͳ͍

    ɹ͜ͷ.BUFSJBMͷ্Ͱ3JQQMF& ff FDU͕ඳը͞ΕΔ λονΠϕϯτ͕*OL8FMM͔Β .BUFSJBM΁఻͑ΒΕΔ $PMPSFE#PY
  18. Ripple Effect΋ޮ͔ͤͭͭɺTabBarͷഎܠ৭Λม͍͑ͨ DefaultTabController( length: 2, child: Scaffold( appBar: AppBar( title:

    Text('Title'), bottom: PreferredSize( preferredSize: Size.fromHeight(72), child: ColoredBox( color: Colors.redAccent, child: TabBar( indicatorColor: Colors.amber, tabs: [ Tab(child: Text('Tab A')), Tab(child: Text('Tab B')), ], ), ), ), ), body: TabBarView( children: [ Page1(), Page2(),
  19. Ripple Effect΋ޮ͔ͤͭͭɺTabBarͷഎܠ৭Λม͍͑ͨ  $PMPSFE#PYͷ୅ΘΓʹɺ 
 *OLͰ5BC#BSΛғΉ  *OLͰഎܠ৭Λࢦఆ͢Δ DefaultTabController( length:

    2, child: Scaffold( appBar: AppBar( title: Text('Title'), bottom: PreferredSize( preferredSize: Size.fromHeight(72), child: ColoredBox( color: Colors.redAccent, child: TabBar( indicatorColor: Colors.amber, tabs: [ Tab(child: Text('Tab A')), Tab(child: Text('Tab B')), ], ), ), ), ), body: TabBarView( children: [ Page1(), Page2(), child: Ink(
  20. Ripple Effect΋ޮ͔ͤͭͭɺTabBarͷഎܠ৭Λม͍͑ͨ "QQ#BS .BUFSJBM 5BC#BS *OL8FMM ɹ*OLͰඳը͍ͨ͠΋ͷ %FDPSBUJPO Λఆٛ *OL

    ʲ*OLͷ໾ׂʳ $PMPSFE#PY
  21. Ripple Effect΋ޮ͔ͤͭͭɺTabBarͷഎܠ৭Λม͍͑ͨ "QQ#BS .BUFSJBM 5BC#BS *OL8FMM ɹ͜ͷ.BUFSJBMͷ্Ͱ%FDPSBUJPO͕ඳը͞ΕΔ λονΠϕϯτͷ3JQQMF& ff FDU΋

    มΘΒͣ.BUFSJBMͷ্ *OL ஫ʣ͜ͷ৔߹΋ɺ.BUFSJBMͷ্ʹ ෆಁ໌ͳ8JEHFUΛ͓͘͜ͱ͸ग़དྷͳ͍ ʲ*OLͷ໾ׂʳ
  22. ׬੒ʁ DefaultTabController( length: 2, child: Scaffold( appBar: AppBar( title: Text('Title'),

    bottom: PreferredSize( preferredSize: Size.fromHeight(72), child: Ink( color: Colors.redAccent, child: TabBar( indicatorColor: Colors.amber, tabs: [ Tab(child: Text('Tab A')), Tab(child: Text('Tab B')), ], ), ), ), ), body: TabBarView( children: [ Page1(), Page2(), ], JOEJDBUPS$PMPSͷԫ৭͕ 
 ൓ө͞Εͣɺന͘ͳ͍ͬͯΔ
  23. IndicatorColorͷṖ Decoration get _indicator { if (widget.indicator != null) return

    widget.indicator; final TabBarTheme tabBarTheme = TabBarTheme.of(context); if (tabBarTheme.indicator != null) return tabBarTheme.indicator; Color color = widget.indicatorColor ?? Theme.of(context).indicatorColor; // ThemeData tries to avoid this by having indicatorColor avoid being the // primaryColor. However, it's possible that the tab bar is on a // Material that isn't the primaryColor. In that case, if the indicator // color ends up matching the material's color, then this overrides it. // When that happens, automatic transitions of the theme will likely look // ugly as the indicator color suddenly snaps to white at one end, but it's // not clear how to avoid that any further. // // The material's color might be null (if it's a transparency). In that case // there's no good way for us to find out what the color is so we don't. if (color.value == Material.of(context).color?.value) color = Colors.white; 5BC#BSͷதͷɺJOEJDBUPSͷॲཧ 'MVUUFSҎલ IUUQTHJUIVCDPN fl VUUFS fl VUUFSCMPCQBDLBHFT fl VUUFSMJCTSDNBUFSJBMUBCTEBSU
  24. IndicatorColorͷṖ Decoration get _indicator { if (widget.indicator != null) return

    widget.indicator; final TabBarTheme tabBarTheme = TabBarTheme.of(context); if (tabBarTheme.indicator != null) return tabBarTheme.indicator; Color color = widget.indicatorColor ?? Theme.of(context).indicatorColor; // ThemeData tries to avoid this by having indicatorColor avoid being the // primaryColor. However, it's possible that the tab bar is on a // Material that isn't the primaryColor. In that case, if the indicator // color ends up matching the material's color, then this overrides it. // When that happens, automatic transitions of the theme will likely look // ugly as the indicator color suddenly snaps to white at one end, but it's // not clear how to avoid that any further. // // The material's color might be null (if it's a transparency). In that case // there's no good way for us to find out what the color is so we don't. if (color.value == Material.of(context).color?.value) color = Colors.white; *OEJDBUPS$PMPS͕QSJNBSZ$PMPSͱҰக͢Δ৔߹ɺ നͰ্ॻ͖͍ͯ͠Δ 5BC#BSͷதͷɺJOEJDBUPSͷॲཧ 'MVUUFSҎલ
  25. IndicatorColorͷṖ Decoration get _indicator { if (widget.indicator != null) return

    widget.indicator; final TabBarTheme tabBarTheme = TabBarTheme.of(context); if (tabBarTheme.indicator != null) return tabBarTheme.indicator; Color color = widget.indicatorColor ?? Theme.of(context).indicatorColor; // ThemeData tries to avoid this by having indicatorColor avoid being the // primaryColor. However, it's possible that the tab bar is on a // Material that isn't the primaryColor. In that case, if the indicator // color ends up matching the material's color, then this overrides it. // When that happens, automatic transitions of the theme will likely look // ugly as the indicator color suddenly snaps to white at one end, but it's // not clear how to avoid that any further. // // The material's color might be null (if it's a transparency). In that case // there's no good way for us to find out what the color is so we don't. if (color.value == Material.of(context).color?.value) color = Colors.white; *OEJDBUPS$PMPS͕QSJNBSZ$PMPSͱҰக͢Δ৔߹ɺ നͰ্ॻ͖͍ͯ͠Δ JOEJDBUPS͸جຊతʹQSJNBSZ$PMPSͷ ্ʹඳը͞ΕΔ͜ͱΛ૝ఆ͍ͯ͠ΔͨΊɺ ࣗવͳڍಈ 5BC#BSͷதͷɺJOEJDBUPSͷॲཧ 'MVUUFSҎલ
  26. IndicatorColorͷṖ Decoration get _indicator { …(ུ) Color color = widget.indicatorColor

    ?? Theme.of(context).indicatorColor; // ThemeData tries to avoid this by having indicatorColor avoid being the // primaryColor. However, it's possible that the tab bar is on a // Material that isn't the primaryColor. In that case, if the indicator // color ends up matching the material's color, then this overrides it. // When that happens, automatic transitions of the theme will likely look // ugly as the indicator color suddenly snaps to white at one end, but it's // not clear how to avoid that any further. // // The material's color might be null (if it's a transparency). In that case // there's no good way for us to find out what the color is so we don't. // // TODO(xu-baolin): Remove automatic adjustment to white color indicator // with a better long-term solution. // https://github.com/flutter/flutter/pull/68171#pullrequestreview-517753917 if (widget.automaticIndicatorColorAdjustment && color.value == Material.of(context)?.color?.value) color = Colors.white; 5BC#BSͷதͷɺJOEJDBUPSͷॲཧ 'MVUUFSd IUUQTHJUIVCDPN fl VUUFS fl VUUFSCMPCQBDLBHFT fl VUUFSMJCTSDNBUFSJBMUBCTEBSU 50%0ίϝϯτͱҰॹʹϑϥά͕௥Ճ͞Ε͍ͯΔ
  27. IndicatorColorͷṖ /// Whether this tab bar should automatically adjust the

    [indicatorColor]. /// /// If [automaticIndicatorColorAdjustment] is true, /// then the [indicatorColor] will be automatically adjusted to [Colors.white] /// when the [indicatorColor] is same as [Material.color] of the [Material] parent widget. final bool automaticIndicatorColorAdjustment; BVUPNBUJD*OEJDBUPS$PMPS"EKVTUNFOUͱ͍͏ϑϥά͕௥Ճ USVFͷ৔߹͸طଘͷΑ͏ʹɺJOEJDBUPS$PMPSQSJNBSZ$PMPSͷ৔߹ʹ JOEJDBUPS$PMPSΛࣗಈͰനʹ͢ΔڍಈʹͳΔɻ ͜ΕΛ๷͍͗ͨ৔߹͸ɺϑϥάΛGBMTFʹ͢Δ͜ͱͰରԠՄೳ
  28. IndicatorColorͷṖ BVUPNBUJD*OEJDBUPS$PMPS"EKVTUNFOUͱ͍͏ϑϥά͕௥Ճ 8PSLBSPVOEͱͯ͠͸ྑ͍͕ɺࠜຊతͳղܾࡦΛ୳͍ͯ͠ΔΑ͏ͳͷͰ ࠓޙมߋͷՄೳੑ΋͋Γͦ͏ IUUQTHJUIVCDPN fl VUUFS fl VUUFSQVMMQVMMSFRVFTUSFWJFX

  29. IndicatorColorΛ൓өͤ͞ΔͨΊʹ  *OLͰ͸ͳ͘ɺ.BUFSJBM΢ΟδΣοτΛ࢖͏  *OEJDBUPSΛ%FDPSBUJPOͱͯ͠ઃఆ͢Δ  BVUPNBUJD*OEJDBUPS$PMPS"EKVTUNFOUϑϥάΛ࢖͏ 'MVUUFSҎ߱ʣ

  30. IndicatorColorΛ൓өͤ͞ΔͨΊʹ  *OLͰ͸ͳ͘ɺ.BUFSJBM΢ΟδΣοτΛ࢖͏ DefaultTabController( length: 2, child: Scaffold( appBar: AppBar(

    title: Text('Title'), bottom: PreferredSize( preferredSize: Size.fromHeight(72), child: Ink( child: Material( color: Colors.redAccent, child: TabBar( indicatorColor: Colors.amber, tabs: [ Tab(child: Text('Tab A')), Tab(child: Text('Tab B')), ], ), ), ), ), body: TabBarView( 5BC#BS͕ࢀর͢Δ.BUFSJBMͷ DPMPS͕มΘͬͨͨΊɺ JOEJDBUPS$PMPS͕ന্͘ॻ͖͞ Εͳ͍
  31. IndicatorColorΛ൓өͤ͞ΔͨΊʹ  *OEJDBUPSΛ%FDPSBUJPOͱͯ͠ઃఆ͢Δ DefaultTabController( length: 2, child: Scaffold( appBar: AppBar(

    title: Text('Title'), bottom: PreferredSize( preferredSize: Size.fromHeight(72), child: Ink( color: Colors.redAccent, child: TabBar( indicatorColor: Colors.amber, indicator: UnderlineTabIndicator( borderSide: BorderSide( width: 2, color: Colors.amber, ), ), tabs: [ Tab(child: Text('Tab A')), Tab(child: Text('Tab B')), ], ࣗલͰ%FDPSBUJPOΛ࡞Ε͹ɺ ࣗಈͰന্͘ॻ͖͞ΕΔ͜ͱ΋ ͳ͍
  32. Summary • Ripple Effect͸Material΢ΟδΣοτͷ্Ͱඳը͞ΕΔͨΊɺ 
 Material΢ΟδΣοτͷ্ʹෆಁ໌ͳ΢ΟδΣοτ͕ଘࡏ͢Δͱ 
 Ripple Effect͕ݟ͑ͳ͘ͳͬͯ͠·͏ •

    ରԠํ๏ͱͯ͠͸ɺෆಁ໌ͳ΢ΟδΣοτΛInkͰ୅ସ͢Δɺ 
 ·ͨ͸Material΢ΟδΣοτΛ഑ஔ͢Δ • TabBarͷIndicator͸ɺMaterial΢ΟδΣοτͷcolorͱಉ͡৭ʹઃఆ͢Δͱ 
 ࣗಈతʹന͘ͳͬͯ͠·͏ͷͰ஫ҙ
  33. Thank you for your attention.

  34. <'MVUUFS>5BC#BSͷഎܠ৭Λ"QQ#BSͱҟͳΔ৭ʹมߋ͢Δ IUUQTRJJUBDPNNLPTVLFJUFNTFEFGEFG <'MVUUFS>*OL3FTQPOTFͱ*OL8FMMͱ*OLɺҧ͍Λઆ໌Ͱ͖·͔͢ʁ IUUQTRJJUBDPNNLPTVLFJUFNTFEGC ؔ࿈ϦϯΫ