颤振中的透明底部导航栏

时间:2019-01-25 14:11:53

标签: dart flutter flutter-layout

我是新来的人。我正在尝试实现此用户界面

screenshot

我还没有发现使用完整的解决方案来在flutter中创建透明的底部导航栏。

我尝试使用

BottomNavigationBarItem(
        backgroundColor: Colors.transparent,
        icon: e,
        activeIcon: _activeIcons[_index],
        title: Text(
          title[_index],
          style: AppStyle.tabBarItem,
        ),
      )

但这似乎不起作用。请帮忙。

9 个答案:

答案 0 :(得分:3)

这就是我实现这一目标的方式

    return Scaffold(
      body: Builder(
        builder: (context) => Container(
          decoration: bgAuthenticationDecoration(),
          child: _HomeBodyWidget(_currentIndex),
        ),
      ),
      bottomNavigationBar: BottomNavigationBar(items: <BottomNavigationBarItem>[
        BottomNavigationBarItem(icon: Icon(Icons.home,),title: Container()),
        BottomNavigationBarItem(icon: Icon(Icons.message),title: Container()),
        BottomNavigationBarItem(icon: Icon(Icons.list),title: Container()),
        BottomNavigationBarItem(icon: Icon(Icons.favorite),title: Container()),
        BottomNavigationBarItem(icon: Icon(Icons.supervised_user_circle),title: Container()),
      ],
      backgroundColor:Colors.black.withOpacity(0.1),),
      extendBodyBehindAppBar: true,
      extendBody: true,
    );

然后,您必须在应用程序主题中将画布颜色设置为透明。

canvasColor: Colors.transparent

希望这会有所帮助。

祝您编程愉快!

答案 1 :(得分:3)

给出的答案中的任何一个都不对我有用,我发现很重要的一点:您必须添加属性extendBody: true

如果为true,并且指定了bottomNavigationBar或persistentFooterButtons,则然后主体将扩展到脚手架的底部,而不是仅扩展到bottomNavigationBar或persistentFooterButtons的顶部。

当bottomNavigationBar具有非矩形形状(例如CircularNotchedRectangle)时,此属性通常很有用,该形状会在条的顶部边缘添加FloatingActionButton大小的槽口。在这种情况下,指定extendBody:true可确保通过底部导航栏的槽口可见支架的身体

连同backgroundColor: Color(0x00ffffff),

NB:0x的颜色是十六进制的ARGB值(0xAARRGGBB),因此ffffff之前的00表示最大的透明度,您可以通过将00增加到ff(十六进制的255)来增加不透明度。

enter image description here

完整代码示例:

import 'package:flutter/material.dart';

class NavigationBar extends StatefulWidget {
    static int _selectedIndex = 0;

    @override
    NavigationBarState createState() => NavigationBarState();
}

class NavigationBarState extends State<NavigationBar> {
    void _onItemTapped(int index) {
        setState(() {
            NavigationBar._selectedIndex = index;
        });
    }

    @override
    Widget build(BuildContext context) {

        return BottomNavigationBar(
            currentIndex: NavigationBar._selectedIndex,
            selectedItemColor: Colors.amber[800],
            onTap: _onItemTapped,
            backgroundColor: Color(0x00ffffff), // transparent
            type: BottomNavigationBarType.fixed,
            unselectedItemColor: Colors.blue,
            items: const <BottomNavigationBarItem>[
                BottomNavigationBarItem(
                    icon: Icon(Icons.home),
                    title: Text('Home'),
                ),
                BottomNavigationBarItem(
                    icon: Icon(Icons.grade),
                    title: Text('Level'),
                ),
                BottomNavigationBarItem(
                    icon: Icon(Icons.notifications),
                    title: Text('Notification'),
                ),
                BottomNavigationBarItem(
                    icon: Icon(Icons.school),
                    title: Text('Achievments'),
                ),
                BottomNavigationBarItem(
                    icon: Icon(Icons.settings),
                    title: Text('Settings'),
                ),
            ]
        );
    }

    @override
    Size get preferredSize => const Size.fromHeight(kToolbarHeight);
}

然后在其中让MaterialApp返回:

return MaterialApp(
                home: Scaffold(
                    extendBody: true, // very important as noted
                    bottomNavigationBar: NavigationBar, // here you make use of the transparent bar.
                    body: Container(
                        decoration: BoxDecoration(
                            image: DecorationImage(
                                image: ExactAssetImage("assets/background.png"), // because if you want a transparent navigation bar I assume that you have either a background image or a background color.
                                fit: BoxFit.fill
                            ),
                        ),
                        child: Container(
                              // the body of your app
                        ),
                    ),
                ),
            );
        }
    }

我希望这会有所帮助。

答案 2 :(得分:2)

我尝试使用注释中讨论的Stack方法:

<xsl:for-each select="/Documents/Document/Invoice/Tables/Table/TableRow">
    <cac:InvoiceLine>
        <cbc:InvoicedQuantity>
            <xsl:value-of select="Field[@Type='LIT_DeliveredQuantity']"/>
        </cbc:InvoicedQuantity>
    <xsl:for-each select="../../../Fields/Field[@Type='BTWverlegd' and @TextDetail='AE']">
            <cac:TaxTotal>
                <cac:TaxSubtotal>
                    <cbc:TaxableAmount>
                        <xsl:for-each select="/Documents/Document/Invoice/Tables/Table/TableRow">
                            <xsl:value-of select="/Documents/Document/Invoice/Tables/Table/TableRow/Field[@Type='LIT_VatExcludedAmount']"/>
                        </xsl:for-each>
                    </cbc:TaxableAmount>
                </cac:TaxSubtotal>
            </cac:TaxTotal>
        </xsl:for-each>
    </cac:InvoiceLine>
</xsl:for-each>

transparent bottom nav

编辑:<Invoice> <cac:InvoiceLine> <cbc:InvoicedQuantity>3.00</cbc:InvoicedQuantity> <cac:TaxTotal> <cac:TaxSubtotal> <cbc:TaxableAmount currencyID="EUR">6.75</cbc:TaxableAmount> </cac:TaxSubtotal> </cac:TaxTotal> </cac:InvoiceLine> <cac:InvoiceLine> <cac:TaxTotal> <cbc:InvoicedQuantity>5.00</cbc:InvoicedQuantity> <cac:TaxSubtotal> <cbc:TaxableAmount currencyID="EUR">140.00</cbc:TaxableAmount> </cac:TaxSubtotal> </cac:TaxTotal> </cac:InvoiceLine> <cac:InvoiceLine> <cbc:ID/> <cbc:InvoicedQuantity>7.00</cbc:InvoicedQuantity> <cac:TaxTotal> <cac:TaxSubtotal> <cbc:TaxableAmount currencyID="EUR">108.50</cbc:TaxableAmount> </cac:TaxSubtotal> </cac:TaxTotal> </cac:InvoiceLine> </Invoice> 具有 Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Stack( children: <Widget>[ Container( decoration: BoxDecoration( image: DecorationImage( image: AssetImage('assets/background.jpg'), fit: BoxFit.cover), ), ), Align( alignment: Alignment.bottomCenter, child: Theme( data: Theme.of(context) .copyWith(canvasColor: Colors.transparent), child: BottomNavigationBar( currentIndex: 0, items: [ BottomNavigationBarItem( icon: Icon(Icons.home), title: Text('Home')), BottomNavigationBarItem( icon: Icon(Icons.home), title: Text('Home')), BottomNavigationBarItem( icon: Icon(Icons.home), title: Text('Home')) ], ))), ], ), ), ); } 的内置标高,您无法更改它,并造成了怪异的阴影效果。如果要删除它,可以像这样实现自己的底部栏:

BottomNavigationBar

transparent nav demo 2

答案 3 :(得分:1)

这是我的方法:

Stack(
      children: <Widget>[
        Container(
          decoration: BoxDecoration(
            image: DecorationImage(
              fit: BoxFit.fill,
              image: NetworkImage("https://cdn.pixabay.com/photo/2018/09/17/16/24/cat-3684184_960_720.jpg")
            )
          ),
        ),
        Column(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            Theme(
              data: Theme.of(context).copyWith(canvasColor: Colors.transparent),
              child: BottomNavigationBar(
                items: [
                  BottomNavigationBarItem(
                      icon: Icon(Icons.photo_camera), title: Text("Test")),
                  BottomNavigationBarItem(
                      icon: Icon(Icons.photo_camera), title: Text("Test")),
                ],
              ),
            )
          ],
        )
      ],
    );

这将用背景图像(底部层)和位于内容与end对齐的列内的底部导航栏填充整个屏幕(图像纯属琐碎,但您会得到东西)。

出于完成目的,我将在给出的解释下粘贴到原始问题的评论中。

  

更深入地思考,我意识到这将不一样   所需的结果,因为两个女孩的形象将高于   导航栏。我建议对两个女孩图像使用堆栈   作为底层(堆栈的底部)和全屏列   将MainAxisSize设置为MainAxisSize.max并将MainAxisAlignment设置为   MainAxisAlignment.end。我可以在答案中写出来,但我无法测试   现在,所以我宁愿写评论。希望对您有帮助

更新 先前的解决方案仍然具有导航栏阴影。 屏幕的这种构建方法(小部件)没有,因为我已经用BottomNavigationBar实现了自己的Row

@override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Container(
          decoration: BoxDecoration(
              image: DecorationImage(
                  fit: BoxFit.fill,
                  image: NetworkImage(
                      "https://media.idownloadblog.com/wp-content/uploads/2016/04/macinmac-portrat-splash.jpg"))),
        ),
        Column(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                GestureDetector(
                    onTap: () {
                      print("Tap!");
                    },
                    child: Icon(
                      Icons.photo_camera,
                      size: 50,
                    )),
                GestureDetector(
                    onTap: () {
                      print("Tap!");
                    },
                    child: Icon(
                      Icons.photo_camera,
                      size: 50,
                    )),
                GestureDetector(
                    onTap: () {
                      print("Tap!");
                    },
                    child: Icon(
                      Icons.photo_camera,
                      size: 50,
                    )),
                GestureDetector(
                    onTap: () {
                      print("Tap!");
                    },
                    child: Icon(
                      Icons.photo_camera,
                      size: 50,
                    )),
              ],
            )
          ],
        )
      ],
    );

这是我手机上的屏幕截图:

Example

奖金

您可以通过致电实现全屏显示

SystemChrome.setEnabledSystemUIOverlays([]);

来源:here

答案 4 :(得分:0)

我的高级解决方案:

'use strict';
const Hapi = require('hapi');
const Basic = require('hapi-auth-basic');
const server = new Hapi.Server();
server.connection({
    port: 2090,
    host: 'localhost'
});


var vorpal = require('vorpal')();
const chalk = vorpal.chalk;
var fs = require("fs");

var utenti = [{
        name: 'a',
        pass: 'b'
    },
    {
        name: 'c',
        pass: 'd'
    }
];

const users = {
    john: {
        username: 'john',
        password: 'secret',
        name: 'John Doe',
        id: '2133d32a'
    },
    paul: {
        username: 'paul',
        password: 'password',
        name: 'Paul Newman',
        id: '2133d32b'
    }
};

var messaggi = [{
        destinazione: 'a',
        sorgente: 'c',
        messsaggio: 'ciao'
    },
    {
        destinazione: 'a',
        sorgente: 'c',
        messsaggio: 'addio'
    },
    {
        destinazione: 'c',
        sorgente: 'a',
        messsaggio: 'arrivederci'
    }
];

var login = '';
var loggato = false;

vorpal
    .command('login <name> <pass>')
    .description('Effettua il login al sistema')
    .action(function (args, callback) {
        loggato = false;
        utenti.forEach(element => {
            if ((element.name == args.name) && (element.pass == args.pass)) {
                loggato = true;
                login = args.name;
                console.log("Accesso effettuato");
            }
        });
        if (!loggato)
            console.log("Login e Password errati");
        callback();
    });

vorpal
    .command('leggi')
    .description('Leggi i messaggi ricevuti')
    .action(function (args, callback) {
        if (loggato) {
            var estratti = messaggi.filter(function (element) {
                return element.destinazione == login;
            });

            estratti.forEach(element => {
                console.log("mittente : " + element.sorgente);
                console.log(chalk.red(element.messsaggio));
            });
        } else {
            console.log("Devi prima loggarti");
        }
        callback();
    });

vorpal
    .command('invia <dest> "<messaggio>"')
    .description('Invia un messaggio ad un altro utente')
    .action(function (args, callback) {
        if (loggato) {
            var trovato = utenti.find(function (element) {
                return element.name == args.dest;
            });
            if (trovato != undefined) {
                messaggi.push({
                    destinazione: args.dest,
                    sorgente: login,
                    messsaggio: args.messaggio
                });
                console.log(messaggi);
            }
        } else {
            console.log("Devi prima loggarti");
        }
        callback();
    });

vorpal
    .command('crea <login> <pass>')
    .description('Crea un nuovo utente')
    .action(function (args, callback) {
        var trovato = utenti.find(function (element) {
            return element.name == args.login;
        });
        if (trovato == undefined) {
            utenti.push({
                name: args.login,
                pass: args.pass
            });
            console.log(utenti);
        }
        callback();
    });

vorpal
    .command('file leggi utenti')
    .description('Legge il file utenti')
    .action(function (args, callback) {
        var contents = fs.readFileSync("utenti.json");
        utenti = JSON.parse(contents);
        callback();
    });

vorpal
    .command('file scrivi utenti')
    .description('Scrive il file utenti')
    .action(function (args, callback) {
        var jsontostring = JSON.stringify(utenti);
        fs.writeFile('utenti.json', jsontostring, function (err) {
            if (err) {
                return console.error(err);
            }
        });
        callback();
    });

vorpal
    .command('file leggi messaggi')
    .description('Legge il file messaggi')
    .action(function (args, callback) {
        var contents = fs.readFileSync("messaggi.json");
        messaggi = JSON.parse(contents);
        callback();
    });

vorpal
    .command('file scrivi messaggi')
    .description('Scrive il file messaggi')
    .action(function (args, callback) {
        var jsontostring = JSON.stringify(messaggi);
        fs.writeFile('messaggi.json', jsontostring, function (err) {
            if (err) {
                return console.error(err);
            }
        });
        callback();
    });

// leggi file , scrivi file

vorpal
    .delimiter(chalk.yellow('messaggi$'))
    .show();




const validate = function (request, username, password, callback) {
    loggato = false;


    utenti.forEach(element => {
        if ((element.name == username) && (element.pass == password)) {
            loggato = true;
            console.log("Accesso effettuato");
            return callback(null, true, {
                name: username
            })
        }
    });
    if (!loggato)
        return callback(null, false);
};

server.register(Basic, function (err) {
    if (err) {
        throw err;
    }
});

server.auth.strategy('simple', 'basic', {
    validateFunc: validate
});



server.route({
    method: 'GET',
    path: '/',
    config: {
        auth: 'simple',
        handler: function (request, reply) {
            reply('hello, ' + request.auth.credentials.name);
        }
    }
});

//route scrivere
server.route({
    method: 'POST',
    path: '/invia',
    config: {
        auth: 'simple',
        handler: function (request, reply) {
            //console.log("Received POST from " + request.payload.name + "; id=" + (request.payload.id || 'anon'));
            var payload = encodeURIComponent(request.payload)
            console.log(request.payload);
            console.log(request.payload.dest);
            console.log(request.payload.messaggio);
            messaggi.push({
                destinazione: request.payload.dest,
                sorgente: request.auth.credentials.name,
                messsaggio: request.payload.messaggio
            });
            var jsontostring = JSON.stringify(messaggi);
            fs.writeFile('messaggi.json', jsontostring, function (err) {
                if (err) {
                    return console.error(err);
                }
            });
            console.log(messaggi);
            reply(messaggi[messaggi.length - 1]);

        }
    }
});


//route leggere (json)
server.route({
    method: 'GET',
    path: '/messaggi',
    config: {
        auth: 'simple',
        handler: function (request, reply) {
            messaggi = fs.readFileSync("messaggi.json");
            var estratti = messaggi.filter(function (element) {
                return element.destinazione == request.auth.credentials.name;
            });
            var s = [];

            console.log(request.auth.credentials.name);
            console.log(estratti.length);
            estratti.forEach(element => {

                s.push(element);

                //fare l'array con stringify
                //s+="mittente : "+element.sorgente+": "+element.messsaggio+"\n";

            });
            var a = JSON.stringify(s);
            console.log(a);
            console.log(s);
            reply(a);
        }
    }
});



server.start(function () {
    console.log('Hapi is listening to ' + server.info.uri);
});

function EseguiSql(connection, sql, reply) {
    var rows = [];
    request = new Request(sql, function (err, rowCount) {
        if (err) {
            console.log(err);
        } else {
            console.log(rowCount + ' rows');
            console.log("Invio Reply")
            reply(rows);
        }
    });

    request.on('row', function (columns) {
        var row = {};
        columns.forEach(function (column) {
            row[column.metadata.colName] = column.value;
        });
        rows.push(row);
    });

    connection.execSql(request);
}

server.route({
    method: 'POST',
    path: '/query',
    handler: function (request, reply) {
        // Qui dovrebbe cercare i dati nel body e rispondere con la query eseguita
        var connection = new Connection(config);

        // Attempt to connect and execute queries if connection goes through
        connection.on('connect', function (err) {
            if (err) {
                console.log(err);
            } else {

                console.log('Connected');
                console.log(request.payload.sql);
                EseguiSql(connection, request.payload.sql, reply);
            }
        });

    }
});

server.connection({
    host: process.env.HOST || 'localhost',
    port: process.env.PORT || 8080
});

var config = {
    userName: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    server: process.env.DB_SERVER,
    options: {
        database: process.env.DB_NAME,
        encrypt: true
    }
}

这个想法是一个堆栈,其底部具有可滚动的视图,顶部具有对齐的自定义底部栏

答案 5 :(得分:0)

在新版本的flutter(1.2.1)中,有一个用于海拔的参数,您可以将 海拔:0.0

答案 6 :(得分:0)

您可以做类似...

不要忘记设置elevation: 0并使用导入 import 'package:flutter/services.dart';

隐藏状态栏

void main() {
  SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]);
  runApp(MaterialApp(
     home: MyApp()));
}

BottomNavigationBar透明

BottomNavigationBar(
  backgroundColor: Colors.black.withOpacity(0.1), //here set your transparent level
  elevation: 0,
);

这是完整的代码

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Stack(
      children: <Widget>[
        Container(
         child: Image.network("https://picsum.photos/660/1420"),
        ),
        Align(
            alignment: Alignment.bottomCenter,
            child: BottomNavigationBar(
              backgroundColor: Colors.black.withOpacity(0.1), //here set your transparent level
              elevation: 0,
              selectedItemColor:  Colors.blueAccent,
              unselectedItemColor: Colors.white,
              type: BottomNavigationBarType.fixed,
              currentIndex: 0,
              showSelectedLabels: false,
              showUnselectedLabels: false,
              items: [
                BottomNavigationBarItem(
                    icon: Icon(Icons.notifications_none, size: 30), title: Text('Notifications')),
                BottomNavigationBarItem(
                    icon: Icon(Icons.search, size: 30), title: Text('Search')),
                BottomNavigationBarItem(
                    icon: Icon(Icons.perm_identity, size: 30), title: Text('User'))
              ],
            )),
      ],
    ),
  );
}

enter image description here

答案 7 :(得分:0)

Scaffold(  
  floatingActionButton: _buildTransparentButton()
)

您可以尝试浮动操作按钮。

答案 8 :(得分:-2)

找到了透明BottomNavigationBar的解决方案。

  1. 使用快捷方式 Ctrl + B 打开BottomNavigationBar的源代码。
  2. 滚动浏览文件,您将找到一个名为Widget build的方法。
  3. 基于此,您可以找到一个Stack widget,您可以在其中找到一个材质小部件。
  4. 添加shadowColor:Colors.transparent

现在您可以获得透明的BottomNavigationBar