原作者:Mariano Zorrilla
你在大公司工作嗎淘捡?
我知道……你有沒有想過(不止一次)“哦检痰,天哪……早上9點,我的一天已經(jīng)被會議和調(diào)bug擠滿了苇经!"
是的赘理,幾乎每天!
我敢肯定扇单,每次你在無聊的會議中都會去刷朋友圈商模!(同意的點贊)
1.我從哪里開始(問題):
我知道每個人在家里都有很多時間做自己的事情,對吧蜘澜?比如看電視節(jié)目施流、電影、社交媒體……
對于那些有足夠財富的人來說鄙信,通過聊天瞪醋、電子郵件和會議交流的唯一途徑是什么?
2.研究:
我們都喜歡探索装诡,對吧银受?
所以,我想“我怎樣才能把探索和實際產(chǎn)品結(jié)合起來”鸦采。
3.工作時間:
好吧宾巍,我有8個小時的“辦公室工作”。所以渔伯,我沒有太多的Web知識顶霞,因為我主要是一個移動開發(fā)人員,現(xiàn)在他們做了更多的管理工作(我知道雙方的痛苦)锣吼,但我知道Flutter 和Flutter Web目前處于測試版选浑,但,你懂的…玄叠!
4.命名產(chǎn)品:
首先古徒,你要為你的產(chǎn)品想一個好名字!
5.工作诸典,工作描函,工作 !
利用我的空閑時間開始一個新項目總是很有趣的,對吧狐粱?但這一次看起來真的很有潛力,范圍也沒那么大胆数。
選擇的工具肌蜻?!
為什么必尼?因為開始一個新的項目蒋搜、設(shè)計和實際完成都很容易篡撵!
它的發(fā)展實在是太快了:身為移動開發(fā)者,Web對我來說有點不同豆挽,即使我們每天都在使用它育谬,但我們需要考慮的路線(路徑)比以往任何時候都多!不僅僅是深層次的聯(lián)系帮哈。
我們在紐約和西蒙以及弗雷特紐約的朋友們開完會后膛檀,我突然想到了一個主意。
我的解決方案提供了一個小型的StatefulWidget導航器娘侍,沒有什么新奇之處咖刃,也不是世界上最干凈的工作:
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'TMSBAE',
onGenerateRoute: (settings) => NavigatorRoute.route(settings.name),
);
}
}
每一條路徑都將來自onGenerateRoute,然后將那個壞小子解析到我們的導航器中憾筏。
一旦我走上這條路嚎杨,我就使用了核心機器學習……或者簡稱If/Else。
@override
void initState() {
super.initState();
Future.delayed(Duration(milliseconds: 0), () {
if (widget.path == '/') {
Navigator.of(context).pushAndRemoveUntil(HomeScreen.route(), (_) => false);
return;
} else if (widget.path == '/join') {
Navigator.of(context).pushAndRemoveUntil(JoinScreen.route(), (_) => false);
return;
} else if (widget.path.contains('/join/')) {
Navigator.of(context).pushAndRemoveUntil(JoinScreen.routeCode(widget.path.split('/')[2]), (_) => false);
return;
} else if (widget.path == '/bae') {
Navigator.of(context).pushAndRemoveUntil(BaeScreen.route(), (_) => false);
} else if (widget.path.contains('/result/')) {
Navigator.of(context).pushAndRemoveUntil(ResultScreen.routeCode(widget.path.split('/')[2]), (_) => false);
} else if (widget.path == '/about') {
} else {
Navigator.of(context).pushAndRemoveUntil(HomeScreen.route(), (_) => false);
return;
}
});
}
} else {
Navigator.*of*(context).pushAndRemoveUntil(HomeScreen.*route*(), (_) => false);
return;
}
});
}
這樣做的目的是避免獲得大量的頁面氧腰,例如:
{URL}/join/djUdmd19m4
Will open:
- “/” 主屏幕
- “/join” join屏幕
- “/join/djUdmd19m4” 我們要打開的實際屏幕枫浙。
這是Flutter開發(fā)人員使用常規(guī)onGenerateRoute方法最常見的問題。
6.設(shè)計:
我很幸運古拴,我也是一個UI/UX設(shè)計/開發(fā)人員……所以自脯,從技術(shù)上說,我是一個全棧開發(fā)人員斤富?膏潮!
我查看了一些設(shè)計網(wǎng)站,以獲得靈感满力,并知道更多與我的設(shè)計焕参,調(diào)色板等…我也看了一些開放源碼字體使用和廢話。
但它們只有一/兩個屏幕大小油额,沒有什么新奇之處叠纷,沒有數(shù)據(jù)庫/業(yè)務邏輯,只是一個使用動畫的簡單而酷的例子潦嘶。
7.編碼:
再說一次涩嚣,即使我有空閑時間,記住掂僵,我有一份全職工作航厚,唯一的空閑時間是我日常工作之外的時間……但足以讓這個新項目迅速完成。
做網(wǎng)站的時候锰蓬,總有一個大字是“響應”的是的幔睬,拜托!記住這個芹扭!我們有智能手機麻顶、筆記本電腦赦抖、臺式機、平板電腦等……您的設(shè)計應該在每一個屏幕上都是實用/有用的辅肾!队萤。
SingleChildScrollView
是其中一個你會經(jīng)常使用的小部件,如果你計劃有動態(tài)列表的話就不是最有用的矫钓,因為這個小部件會把所有東西都加載到內(nèi)存中要尔。
MediaQuery
為了得到尺寸和方位,超級有用份汗,現(xiàn)在每個人都應該知道盈电,但是…是的。
LayoutBuilder
太棒了杯活!在考慮不同的形狀因素和屏幕時匆帚,這一個起到了很好的帶頭作用。
Screens
我有幾個:登錄頁(主屏幕)旁钧,創(chuàng)建屏幕吸重,加入屏幕,結(jié)果屏幕歪今,投票屏幕嚎幸,關(guān)于屏幕。
我在屏幕之間移動的整個業(yè)務邏輯是通過使用:
Navigator.*of*(context).pushAndRemoveUntil
我不想為這個產(chǎn)品保留一個堆棧寄猩,因為我可以用我的AppBar和屏幕上的一些其他元素/按鈕在屏幕之間移動嫉晶,拜托,它變得對PWA更友好了田篇。
PWA
是的替废,flutter支持PWA和否,這兩者并不是不同的東西泊柬,它們只是兩者之間的一個補充椎镣。
如果你使用的是Flutter v.1.5+,請確保運行“Flutter create.”來獲取丟失的文件兽赁。如果由于任何原因您沒有它状答,讓我給您以下片段:
在index.html中<body>
:
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('flutter_service_worker.js');
});
}
</script>
在您的/web文件夾上,您應該有一個manifest.json文件刀崖,如果沒有惊科,它如下所示:
{
"name": "App Name",
"short_name": "App Short Name",
"start_url": ".",
"display": "standalone",
"background_color": "#A83EF6",
"theme_color": "#A83EF6",
"description": "App Description",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
注意那邊的一些元素:
"display": "standalone"
允許您擁有全屏/本地的外觀和感覺。您可以在這里閱讀更多信息
你的圖標應該在/web/icons(或任何其他文件夾中蒲跨,但這樣看起來不錯)中译断,并且將是你的主屏幕/應用程序抽屜中使用的圖標。
對于我那瘋狂又好看的header或悲,我用了:
ClipPath
使用以下代碼段:
class HeaderWaveClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path();
path.lineTo(0, 0);
path.lineTo(0, size.height - 100);
path.cubicTo(
0,
size.height - 90,
size.width * 0.004,
size.height - 70,
size.width * 0.06,
size.height - 75,
);
path.cubicTo(
size.width * 0.07,
size.height - 75,
size.width * 0.14,
size.height - 95,
size.width * 0.12,
size.height - 65,
);
path.cubicTo(
size.width * 0.12,
size.height - 65,
size.width * 0.08,
size.height - 10,
size.width / 3 * 0.98,
size.height - 40,
);
path.cubicTo(
(size.width / 3) * 1.08,
size.height - 40,
(size.width / 3) - 60,
size.height - 5,
(size.width / 3) + 100,
size.height - 5,
);
path.cubicTo(
(size.width / 3) * 1.8,
size.height - 5,
(size.width / 2) * 1.6,
size.height,
(size.width / 2) * 1.52,
size.height - 30,
);
path.cubicTo(
(size.width / 2) * 1.52,
size.height - 35,
(size.width / 2) * 1.4,
size.height - 60,
size.width - (size.width * 0.05),
size.height - 60,
);
path.cubicTo(
size.width - (size.width * 0.05),
size.height - 60,
size.width,
size.height - 60,
size.width,
size.height - 90,
);
path.lineTo(size.width, 0);
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
我花了幾個小時來解決這個問題……數(shù)學很有趣孙咪,但是……是的,花了幾個小時讓它在每一個屏幕上都反應靈敏巡语,看起來很漂亮翎蹈。
我說過每件事都花了我大約12個小時的編碼,而其中很多時間是在2天的工作框架內(nèi)進行設(shè)計+測試男公。
在Firebase上托管花了我?guī)酌腌姷臅r間(字面上)荤堪,而且由于G域的存在,使用我自己的域非常簡單枢赔。
8. 裂變傳播澄阳?(希望如此)
我知道有一個特定的網(wǎng)站有我需要的東西來發(fā)布我的新創(chuàng)作,那就是Product Hunt - The best new products in tech.
每一個新的/酷的/怪異的產(chǎn)品/項目都結(jié)束了踏拜,我想知道那是什么感覺碎赢!我想創(chuàng)建我的第一個病毒產(chǎn)品后,這么多年的編碼沒有許多酷/有趣的想法速梗。
這個過程相當直接:
- 創(chuàng)建帳戶
- 等待1周(或關(guān)注他們的時事通訊以獲得即時訪問)
- 發(fā)布產(chǎn)品
- 關(guān)注每個細節(jié)(標題肮塞、描述、圖標姻锁、截圖/視頻等)
- 發(fā)布U碚浴(你可以安排這個)
最后的想法
這真的很有趣,希望人們能經(jīng)常使用它位隶!我知道這只是一個迷因拷窜,但這個有潛力,也許團隊會在他們的日歷中包含我自動生成的鏈接涧黄,這樣每個人都有機會決定會議是否應該是電子郵件篮昧。
PS:我是黑胡桃實驗室社區(qū)的一名成員,最近經(jīng)常在看一些老外做的有趣的人工智能項目弓熏,如果有興趣或疑問可以在評論區(qū)留言或私信與我交流鴨~