Flutter七日遊第七天:2018-12-22 天氣:雨-陰
零、前言
最後一天了,今天將把前六天的零碎知識整合起來,以及未涉及的零碎知識css
最後會附上源碼,在github,我按天分包稍微整理了一下,順手Star一下吧
順便提一下:Dart語法的相關測試在test包的base裏
(怕大家找不到)
與Android代碼交互後感受flutter仍是蠻能夠的,惋惜沒條件玩ios,否則豈不是能夠通殺
(給我七天或許能夠把ios跑一圈,之後有錢再說吧)前端
留圖鎮樓:分類效果和查詢效果
- | - |
---|---|
1、字體圖標的相關問題
1.字體圖標:
字體圖標放大不變形,又能改變顏色,主要根據
.ttf
的字體,react
而後圖標算一個文字,根據unicode來對應圖標,就能夠用了。
Icon(Icons.android)
也許你常常用,但內置圖標有限,只能測試玩玩
實際上用仍是須要自定義才行,前端的時候有字體圖標,Flutter應該也行android
//好比咱們常常怎樣用:
Icon(Icons.comment)
複製代碼
2.進入源碼看看:
貌似都是靜態常量,核心在unicode,如
0xe577
,還有就是字體(MaterialIcons
)ios
/// * [design.google.com/icons](https://design.google.com/icons/)
class Icons {
Icons._();
// Generated code: do not hand-edit.
// See https://github.com/flutter/flutter/wiki/Updating-Material-Design-Fonts
// BEGIN GENERATED
/// <i class="material-icons md-36">360</i> — material icon named "360".
static const IconData threesixty = IconData(0xe577, fontFamily: 'MaterialIcons');
/// <i class="material-icons md-36">3d_rotation</i> — material icon named "3d rotation".
static const IconData threed_rotation = IconData(0xe84d, fontFamily: 'MaterialIcons');
/// <i class="material-icons md-36">4k</i> — material icon named "4k".
static const IconData four_k = IconData(0xe072, fontFamily: 'MaterialIcons');
複製代碼
3.怎麼才能自定義字體圖標
玩前端的應該都知道:仍是進入阿里圖標神庫:iconfontgit
4.根據Flutter內置的類,我寫了一個自動代碼生成器
雖然直接也能用,不夠要記住圖標的unicode碼,算了,仍是跟Flutter看齊吧github
注意:爲了簡單使用:拷貝到的位置,命名,請務必和下面保持一致
!保持一致
!
把兩個文件拷貝到對應處,icon_by_toly.dart
寫好(在下面),右鍵運行就自動生成iconfont.dart
了spring
代碼生成器:icon_by_toly.dart
編程
import 'dart:io';
main() {
var result = """import 'package:flutter/widgets.dart';
//Power By 張風捷特烈--- Generated file. Do not edit.
class TolyIcon {
TolyIcon._();
""";
var fileCss = File.fromUri(Uri.parse("${Uri.base}iconfont/iconfont.css"));
if (!fileCss.existsSync()) {
return;
}
var read = fileCss.readAsStringSync();
var split = read.split(".icon-");
split.forEach((str) {
if (str.contains("before")) {
var split = str.split(":");
result += "static const IconData " +
split[0].replaceAll("-", "_") +
" = const IconData(" +
split[2].replaceAll("\"\\", "0x").split("\"")[0] +
", fontFamily: \"TolyIcon\");\n";
}
});
result+="}";
fileCss.delete();
var fileOut = File.fromUri(Uri.parse("${Uri.base}lib/iconfont.dart"));
fileOut.writeAsStringSync(result);
var config="""
fonts:
- family: TolyIcon
fonts:
- asset: iconfont/iconfont.ttf
""";
var yaml = File.fromUri(Uri.parse("${Uri.base}pubspec.yaml"));
if (yaml.readAsStringSync().contains("TolyIcon")) {
return;
}
yaml.writeAsString(config,mode: FileMode.append);
}
複製代碼
pubspec.yaml
的flutter標籤下也會自動生成配置:
fonts:
- family: TolyIcon
fonts:
- asset: iconfont/iconfont.ttf
複製代碼
Icon(TolyIcon.icon_spring_boot)//顏色可自行處理
複製代碼
友情提示:下載以前最好把圖標名字改一下,否則以後找起來費勁json
若是實在不想該,能夠點擊這裏查看名字和圖標的對應狀況
2、綜合小案例
1.初始代碼:主頁面:android_stack.dart
import 'package:flutter/material.dart';
class AndroidPage extends StatefulWidget {
@override
_AndroidPageState createState() => _AndroidPageState();
}
class _AndroidPageState extends State<AndroidPage>
with SingleTickerProviderStateMixin {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
var scaffold = Scaffold(
appBar: AppBar(
title: Text("張風捷特烈"),
),
body: Container(),
floatingActionButton: FloatingActionButton(
onPressed: () {
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
return scaffold;
}
}
複製代碼
2.拼接底部條
2.1:常量的準備:(爲了方便使用或修改)
class ItemBean {
Color color;
IconData iconId;
String info;
ItemBean(this.color, this.iconId, this.info);
}
//底部欄圖標信息
var iconLi=[
ItemBean(Color(0xff8FC552),TolyIcon.android,"Android"),
ItemBean(Color(0xff6BFB00),TolyIcon.icon_spring_boot,"SpringBoot"),
ItemBean(Color(0xff63DAFF),TolyIcon.react,"React"),
ItemBean(Color(0xffF3D861),TolyIcon.biji,"編程隨筆"),
ItemBean(Color(0xff5CEBF2),TolyIcon.daima,"系列文章")
];
複製代碼
2.2:底部欄:
//成員變量
int _curIndex = 0;
//底部欄
var bottomNavigationBar = BottomNavigationBar(
items: iconLi.map((item) {
return BottomNavigationBarItem(
title: Text(
item.info,
style: TextStyle(fontSize: 12, color: Colors.black),
),
icon: Icon(
item.iconId,
color: item.color,
),
backgroundColor: Color(0xffffffff));
}).toList(),
currentIndex: _curIndex,
onTap: _onTapBNB,
);
複製代碼
2.3:底部欄點擊監聽:_onTapBNB
//底部欄點擊監聽
void _onTapBNB(int position) {
_curIndex = position;
setState(() {});
}
複製代碼
3:頁面條目:
第五天寫了幾個條目,如今拿來用(詳細分析見第五天,這裏不廢話了)
靜態填充 | 左側滑欄 |
---|---|
3.1:左側滑欄:left_draw.dart
class LeftDrawPage extends StatefulWidget {
@override
_LeftDrawPageState createState() => _LeftDrawPageState();
}
class _LeftDrawPageState extends State<LeftDrawPage>
with SingleTickerProviderStateMixin {
@override
Widget build(BuildContext context) {
//左邊頭像
var headImg3 = Image.asset(
"images/icon_90.png",
width: 50,
height: 50,
);
//中間的信息
var center3 = Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"張風捷特烈",
style: bigStyle,
),
Row(
children: <Widget>[
Icon(Icons.next_week, size: 15),
pd(Text("創世神 | 無"), l: 5)
],
),
Row(
children: <Widget>[
Icon(Icons.keyboard, size: 15),
pd(Text("海的彼岸有我不曾見證的風采"), l: 5)
],
),
],
);
var rowLine3 = Row(
children: <Widget>[
pda(headImg3, 5),
Expanded(child: pda(center3, 5)),
],
);
var test3 = Card(
child: Container(
height: 95,
color: Colors.white,
padding: EdgeInsets.all(5),
child: rowLine3));
return Drawer(
elevation: 5,
child: Container(
padding: EdgeInsets.only(top: 50),
alignment: AlignmentDirectional.topCenter,
color: Color(0xff99C6F9),
child: test3));
}
}
複製代碼
3.2:列表靜態填充:home_list.dart
class HomeListPage extends StatefulWidget {
@override
_HomeListPageState createState() => _HomeListPageState();
}
class _HomeListPageState extends State<HomeListPage> {
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: 10,
itemBuilder: (BuildContext context, int index) {
return renderItem(index);
},
);
}
renderItem(int index) {
////////////////////////-----------------測試4--------------------------------
var line1_4 = Row(
children: <Widget>[
Image.asset("images/icon_90.png", width: 20, height: 20),
Expanded(
child: pd(Text("張風捷特烈"), l: 5),
),
Text(
"Flutter/Dart",
style: infoStyle,
)
],
);
var center_right = Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
"Flutter第4天--基礎控件(下)+Flex佈局詳解",
style: littelStyle,
maxLines: 2,
),
pd(
Text(
"1.2:優雅地查看:圖片的適應模式--BoxFit1.3:優雅地查看:顏色混合模式--colorBlendMode",
style: infoStyle,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
t: 5),
],
);
//中間的信息
var center4 = Row(
children: <Widget>[
Expanded(child: pda(center_right, 5)),
Image.asset(
"images/wy_300x200.jpg",
width: 80,
height: 80,
fit: BoxFit.fitHeight,
)
],
);
var end4 = Row(
children: <Widget>[
Icon(
Icons.grade,
color: Colors.green,
size: 20,
),
Text(
"1000W",
style: infoStyle,
),
pd(Icon(Icons.tag_faces, color: Colors.lightBlueAccent, size: 20),
l: 15, r: 5),
Text("2000W", style: infoStyle),
],
);
var item4 = Column(
children: <Widget>[line1_4, Expanded(child: center4), end4],
);
var aCard = Card(
child: Container(
height: 160,
color: Colors.white,
padding: EdgeInsets.all(10),
child: item4));
return aCard;
}
}
複製代碼
4.動態數據獲取:
昨天已經把http獲取數據的內容將過了,而且把服務端的數據解析了
今天就是使用這些數據,來填充靜態界面,api接口介紹
和NoteBean
昨天已完成
封裝一個獲取數據的方法:簡單說下用法:
style是類型:Android是A ;SpringBoot是SB ; React 是Re ; 筆記是 Note
offset和num 聯合使用能夠達到分頁效果, 好比offset=24,num=12,就是一頁12條數據的第3頁
import 'dart:convert';
import 'package:http/http.dart' as client;
import 'package:toly/pager/day7/bean.dart';
const BASE_URL = 'http://192.168.43.60:8089';//api接口的域名本身改一下
const API = '/api/android/note/';
Future<List<NoteBean>> get({style = '', offset = 0, num = 1}) async {
var dataLi = <NoteBean>[];
var url = BASE_URL + API + style + "/" + "$offset" + "/" + "$num";
try {
final response = await client.get(url);
if (response.statusCode == 200) {
var result = ResultBean.fromJson(json.decode(response.body));
List data = result.data;
print(NoteBean.fromJson(data[0]).type);
for (int i = 0; i < data.length; i++) {
dataLi.add(NoteBean.fromJson(data[i]));
}
return dataLi;
}
} catch (e) {
print(e);
}
}
複製代碼
5.用一個數據來進行填充測試:
主頁面:android_stack.dart
,initState
的時候獲取數據,並更新狀態
//定義一個成員變量
List<NoteBean> _notes = [];
@override
void initState() {
super.initState();
get(num: 1).then((beanLi) {
_notes = beanLi;
setState(() {});
});
}
複製代碼
列表界面:home_list.dart
:接收主界面傳來的_notes,並渲染數據
class HomeListPage extends StatefulWidget {
List<NoteBean> _notes;
HomeListPage(List<NoteBean> notes) {
_notes = notes;
}
@override
_HomeListPageState createState() => _HomeListPageState();
}
class _HomeListPageState extends State<HomeListPage> {
@override
Widget build(BuildContext context) {
var notes = widget._notes;
return ListView.builder(
itemCount: notes.length,
itemBuilder: (BuildContext context, int index) {
return renderItem(notes[index]);
},
);
}
//渲染條目
renderItem(NoteBean note) {
var line1_4 = Row(
children: <Widget>[
Image.asset("images/icon_90.png", width: 20, height: 20),
Expanded( child: pd(Text("張風捷特烈"), l: 5),),
Text( note.type,style: infoStyle,)
],
);
var center_right = Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[Text(note.name,style: littelStyle,maxLines: 2,),
pd(Text( note.info, style: infoStyle, maxLines: 2,
overflow: TextOverflow.ellipsis, ), t: 5),
],
);
//中間的信息
var center4 = Row(
children: <Widget>[
Expanded(child: pda(center_right, 5)),
Image.network( note.imgUrl,
width: 80, height: 80, fit: BoxFit.fitHeight )
],
);
var end4 = Row(
children: <Widget>[
Icon( Icons.grade, color: Colors.green, size: 20, ),
Text( "1000W", style: infoStyle,),
pd(Icon(Icons.tag_faces, color: Colors.lightBlueAccent, size: 20),
l: 15, r: 5),
Text("2000W", style: infoStyle),
],
);
var item4 = Column(
children: <Widget>[line1_4, Expanded(child: center4), end4],
);
var aCard = Card(
child: Container( height: 160,color: Colors.white,
padding: EdgeInsets.all(10), child: item4));
return aCard;
}
}
複製代碼
如今萬事俱備,東風也到了,num小小動一下:num=30
-- | -- |
---|---|
也許你感受還未開始,但確實已經結束了...
6.底部導航欄的切換:(下面兩個圖同樣的,爲了撐場面...)
剛纔是數據沒有分類型,如今點擊底部導航,按範圍進行展現
get(style: "area/A", num: 30)//這樣就是展現又有安卓類的文章
- | - |
---|---|
android_stack.dart
添加成員變量
這裏我默認加載完,作分頁的話,再添加個_count的成員變量就好了
String style = "area/A";
//頁面打開,默認加載安卓頁
@override
void initState() {
super.initState();
get(style: style, num: 1000).then((beanLi) {
_notes = beanLi;
setState(() {});
});
}
//底部欄點擊監聽---動態改變範圍
void _onTapBNB(int position) {
switch (position) {
case 0:
style = "area/A";
break;
case 1:
style = "area/SB";
break;
case 2:
style = "area/Re";
break;
case 3:
style = "area/Note";
break;
case 4:
style = "area/A";
break;
}
_curIndex = position;
get(style: style, num: 1000).then((beanLi) {
_notes = beanLi;
setState(() {});
});
}
複製代碼
7.底部欄和搜索功能
底部欄用法詳情在第四篇
-- | -- |
---|---|
底部欄:這裏把事件寫在裏面了,你也能夠抽成方法
或者有些控件太長,你也能夠抽出來作變量
var searchSheet = BottomSheet(
onClosing: () {},
builder: (context) => (Card(
color: Color.fromARGB(255, 214, 242, 251),
child: Wrap(
children: <Widget>[
Center(child: pdhv(TextField(
onChanged: (v) {style = "name/" + v;}), h: 60)),
Center(child: pdhv( GestureDetector(child:
Image.asset("images/icon_90.png",width: 50,height: 50 ),
onTap: () {
get(style: style, num: 1000).then((beanLi) {
_notes = beanLi;
setState(() {});
});
},
),
v: 10)),
],
))));
//點擊按鈕彈出:
var scContext; //先聲明一下Scaffold的context
var scaffold = Scaffold(
appBar: AppBar(
title: Text("張風捷特烈"),
),
body: Builder(builder: (context) {
scContext = context;
return HomeListPage(_notes);
}),
floatingActionButton: FloatingActionButton(
onPressed: () {
Scaffold.of(scContext).showBottomSheet(searchSheet.builder);
},
//下面不用修改,略...
複製代碼
Ok,小案例就這樣
3、Android代碼交互
1.最簡單的無參無返回函數調用:兩對應
不得不說:前六天不能彈吐司真是很差受,原生交互確定先拿他開刀
1.1:Android代碼
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "www.toly1994.com/test.名字隨意起";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
if (methodCall.method.equals("showToast")) {
showToast("Hello Flutter,I am in Android");
} else {
result.notImplemented();
}
}
}
);
}
/**
* 顯示吐司
*
* @param msg 信息
*/
public void showToast(String msg) {
Toast toast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
toast.show();
}
}
複製代碼
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
const platform = const MethodChannel("www.toly1994.com/test.名字隨意起");
var toastTest = Center(
child: RaisedButton(
onPressed: () {
platform.invokeMethod("showToast");
},
child: new Text("點擊彈吐司"),
),
);
複製代碼
2.Flutter中傳參,調用Android含參方法:三對應
2.1:Android代碼
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "www.toly1994.com/test.名字隨意起";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
if (methodCall.method.equals("showToast")) {
//解析參數
String msg = methodCall.argument("msg");
showToast(msg);
} else {
result.notImplemented();
}
}
}
);
}
/**
* 顯示吐司
*
* @param msg 信息
*/
public void showToast(String msg) {
Toast toast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);
toast.show();
}
}
複製代碼
2.2:Flutter代碼:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
const platform = const MethodChannel("www.toly1994.com/test.名字隨意起");
var toastTest = Center(
child: RaisedButton(
onPressed: () {
platform.invokeMethod("showToast",{"msg":"Flutter大爺我賞你一口吐司"});
},
child: new Text("點擊彈吐司"),
),
);
複製代碼
2.3:加返回值的方法調用:
舉什麼例子,我想了一會,就來個MD5碼吧
//Activity添加判斷分支
if (methodCall.method.equals("getMD5")) {
String arg = methodCall.argument("arg");
String md5 = getMD5(arg);
result.success(md5);
}
/**
* 獲取一個字符串的Md5值
*
* @param content 內容
* @return Md5值
*/
public String getMD5(String content) {
content = content + "芝麻開門";
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(content.getBytes());
return getHashString(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
private static String getHashString(MessageDigest digest) {
StringBuilder builder = new StringBuilder();
for (byte b : digest.digest()) {
builder.append(Integer.toHexString((b >> 4) & 0xf));
builder.append(Integer.toHexString(b & 0xf));
}
return builder.toString();
}
複製代碼
2.2:Flutter代碼:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
const platform = const MethodChannel("www.toly1994.com/test.名字隨意起");
var toastTest = Center(
child: RaisedButton(
onPressed: () {
var result= platform.invokeMethod("getMD5",{"arg":"https://www.jianshu.com/p/9bac0072d1a0"});
result.then((str){
platform.invokeMethod("showToast",{"msg":str});
});
},
child: new Text("點擊彈吐司"),
),
);
複製代碼
基本上也就這三種狀況
[彩蛋]--之前Mark的一個小點:Card的shape
有人說學習的時候一個問題會牽扯到不少其餘的問題,問題一多就無從下手
我只說一個字:"棧":來最後一波學習看源碼的方法了,走起
1.shape是什麼:形狀
如今的問題棧
可見默認圓角是4的RoundedRectangleBorder
---->[shape屬性]----
/// The default shape is a [RoundedRectangleBorder] with a circular corner
/// radius of 4.0.
final ShapeBorder shape;
---->[RoundedRectangleBorder]----
const RoundedRectangleBorder({
this.side = BorderSide.none,
this.borderRadius = BorderRadius.zero,
//可見有兩個屬性:BorderSide和BorderRadius
---->[BorderSide]----
class BorderSide {
/// Creates the side of a border.
///
/// By default, the border is 1.0 logical pixels wide and solid black.
const BorderSide({
this.color = const Color(0xFF000000),
this.width = 1.0,
this.style = BorderStyle.solid,
---->[BorderRadius]----
class BorderRadius extends BorderRadiusGeometry {
/// Creates a border radius where all radii are [radius].
const BorderRadius.all(Radius radius) : this.only(
topLeft: radius,
topRight: radius,
bottomLeft: radius,
bottomRight: radius,
);
/// Creates a border radius where all radii are [Radius.circular(radius)].
BorderRadius.circular(double radius) : this.all(
Radius.circular(radius),
);
---->[Radius]------
class Radius {
/// Constructs a circular radius. [x] and [y] will have the same radius value.
const Radius.circular(double radius) : this.elliptical(radius, radius);
/// Constructs an elliptical radius with the given radii.
const Radius.elliptical(this.x, this.y);
/// The radius value on the horizontal axis.
final double x;
/// The radius value on the vertical axis.
final double y;
複製代碼
一個shape牽扯出這麼多類,有人可能就
棧溢出
了,仍是使用默認的吧,等一下,且聽我分析
當Radius入問題棧以後,看一下也就是兩個值,就出棧了,BorderRadius跟着也出棧了
BorderSide三個字段,看一下,出棧了,如今棧頂是RoundedRectangleBorder
你還不會嗎?
2. RoundedRectangleBorder改變圓角大小+邊線
var card_shape = Card(
// shape: CircleBorder(side: BorderSide(width: 1)),
shape: RoundedRectangleBorder(
side:BorderSide(color: Color(0xffD516F5),width: 5) ,
borderRadius: BorderRadius.all(Radius.circular(20))),
clipBehavior: Clip.antiAlias,
child: Container(
width: 100,
height: 100,
color: Color(0xffCDECF6),
child: Center(child:Text(
"捷",
style: TextStyle(color: Colors.black,fontSize: 40),
) ,),
));
複製代碼
那彈棧事後問題跑哪裏?
我想應該是臨時知識庫
吧,你解決的問題中獲取的知識,經驗會累積
可能長久不用知識庫裏的知識會漏掉,但印象有的,下一次再入棧,解決起來會更快
在的知識庫裏紮根的知識,那當你遇到時,就不是問題,直接彈棧,這樣想學習是否是也挺好玩的
大神級的Coder知識庫豐富,問題都不是問題,也許偶爾入棧一兩個,但棧很深(感受挺浪費哈)
新手就是棧比較淺,問題多,因此容易StackOver
,因此修煉你容忍問題的能力(棧深)頗有必要
像我這樣不深不淺的剛恰好,會碰到問題,也能一點點解決,一點一點踏上封神之路
但全部的大神也都是重新手這樣過來的,解決問題的能力也不是與生俱來,祝你慢慢彈棧,收穫多多。
3.接下來看ShapeBorder
在棧頂,咱們去瞅瞅
BorderSide如今已經化敵爲友,CircleBorder豈不是秒出棧,而且俘獲
CircleBorder
一枚
並且BorderSide強化+1,知識就是這樣積累的,難道還有別的方法嗎?除非記憶拷貝...
轉一轉當CD背景感受挺不錯
var card_shape = Card(
shape: CircleBorder(side: BorderSide(width: 15,color: Color(0xffF9DFA7))),
clipBehavior: Clip.antiAlias,
child: Container(
width: 100,
height: 100,
color: Color(0xffCDECF6),
child: Center(child:Text(
"捷",
style: TextStyle(color: Colors.black,fontSize: 40),
) ,),
));
複製代碼
4.前方高能,非戰鬥人員帶好零食
其實以爲shape好玩,是在粗略看源碼時,看到了canvas,才mark的
自定義ShapeBorder走起:畫具在手,天下我有
var card_shape = Card(
shape: StarBorder(),
// shape: CircleBorder(side: BorderSide(width: 15,color: Color(0xffF9DFA7))),
// shape: RoundedRectangleBorder(
// side:BorderSide(color: Color(0xffD516F5),width: 5) ,
// borderRadius: BorderRadius.all(Radius.circular(20))),
clipBehavior: Clip.hardEdge,
child: Container(
width: 100,
height: 100,
color: Color(0xffCDECF6),
child: Center(
child: Text(
"捷",
style: TextStyle(color: Colors.black, fontSize: 40),
),
),
));
class StarBorder extends ShapeBorder {
@override
// TODO: implement dimensions
EdgeInsetsGeometry get dimensions => null;
@override
Path getInnerPath(Rect rect, {TextDirection textDirection}) {
// TODO: implement getInnerPath
return null;
}
@override
Path getOuterPath(Rect rect, {TextDirection textDirection}) {
print(rect.right);
return regularPolygonPath(10, 50,x: rect.height/2,y: rect.width/2);
}
@override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {
canvas.translate(50, 50);
// canvas.drawPath(nStarPath(5, 40, 20), new Paint());
}
@override
ShapeBorder scale(double t) {
// TODO: implement scale
return null;
}
}
複製代碼
路徑封裝(稍微優化了一下)
/**
* n角星路徑
*
* @param num 幾角星
* @param R 外接圓半徑
* @param r 內接圓半徑
* @return n角星路徑
*/
Path nStarPath(int num, double R, double r, {x = 0, y = 0}) {
Path path = new Path();
double perDeg = 360 / num; //尖角的度數
double degA = perDeg / 2 / 2;
double degB = 360 / (num - 1) / 2 - degA / 2 + degA;
path.moveTo(cos(_rad(degA)) * R+x, (-sin(_rad(degA)) * R+y));
for (int i = 0; i < num; i++) {
path.lineTo(
cos(_rad(degA + perDeg * i)) * R+x, -sin(_rad(degA + perDeg * i)) * R+y);
path.lineTo(
cos(_rad(degB + perDeg * i)) * r+x, -sin(_rad(degB + perDeg * i)) * r+y);
}
path.close();
return path;
}
/**
* 畫正n角星的路徑:
*
* @param num 角數
* @param R 外接圓半徑
* @return 畫正n角星的路徑
*/
Path regularStarPath(int num, double R,{x = 0, y = 0}) {
double degA, degB;
if (num % 2 == 1) {
//奇數和偶數角區別對待
degA = 360 / num / 2 / 2;
degB = 180 - degA - 360 / num / 2;
} else {
degA = 360 / num / 2;
degB = 180 - degA - 360 / num / 2;
}
double r = R * sin(_rad(degA)) / sin(_rad(degB));
return nStarPath(num, R, r,x: x,y:y);
}
/**
* 畫正n邊形的路徑
*
* @param num 邊數
* @param R 外接圓半徑
* @return 畫正n邊形的路徑
*/
Path regularPolygonPath(int num, double R,{x = 0, y = 0}) {
double r = R * cos(_rad(360 / num / 2)); //!!一點解決
return nStarPath(num, R, r,x: x,y:y);
}
/**
* 角度制化爲弧度制
*
* @param deg 角度
* @return 弧度
*/
double _rad(double deg) {
return deg * pi / 180;
}
複製代碼
師傅領進門,修行在我的
,我已經把功力傳給你了,可否修成正果,就看各自造化。
事了拂衣去,深藏功與名
,Ok,Flutter七日遊,完捷
散花,自認爲沒有爛尾,耶!
後記:捷文規範
1.本文成長記錄及勘誤表
項目源碼 | 日期 | 備註 |
---|---|---|
V0.1-github | 2018-12-22 | Flutter第7天--字體圖標+綜合小案例+Android代碼交互 |
2.更多關於我
筆名 | 微信 | 愛好 | |
---|---|---|---|
張風捷特烈 | 1981462002 | zdl1994328 | 語言 |
個人github | 個人簡書 | 個人掘金 | 我的網站 |
3.聲明
1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大編程愛好者共同交流
3----我的能力有限,若有不正之處歡迎你們批評指證,一定虛心改正
4----看到這裏,我在此感謝你的喜歡與支持
本文同步分享在 博客「張風捷特烈」(JueJin)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。