您当前所在位置: > 爆料站 > 有深度

不用掉一根头发!用Flutter+Dart快速构建一款绝美移动App

时间:2020-03-15 14:53:54  来源:  作者:网络

原标题:不用掉一根头发!用 Flutter + Dart 快速构建一款绝美移动 App

作者 | Wojciech Kuroczycki

译者 | 弯月

出品 | CSDN(ID:CSDNnews)

如今这个时代,与前端或移动相关的新框架层出不穷。所有从事Web开发的人都应该熟悉各种目不暇接的新方法以及针对复杂问题的轻量级解决方案。我们不再因为没有现成的技术而烦恼,相反我们常常因为不知道该选哪种技术而感到头疼。

最近,我偶然间发现了Flutter,于是兴致勃勃地决心一试,看看这种技术是否能够成为强有力的竞争对手,或者甚至作为一种解决方案,让我在进退两难的困境中看到新的希望。

Flutter简介

Flutter是Google出品的移动应用UI SDK。它使用了Dart VM(也是Google出品,专门针对UI进行了优化),帮助我们开发移动设备和台式设备。Dart本身也可用于Web开发,甚至可以与我们非常熟悉的Angular框架配合使用。

Flutter可以通过AoT(提前)编译方式编译成原生机器代码,目的是让应用的运行速度达到最高,同时又不会产生太多开销。

对于开发人员,Flutter提供了JIT(即时)编译器和热重载功能,我们能够在不丢失现有状态的情况下修改应用程序,这点非常实用,因为在复杂的功能中修改一个隐藏得很深的UI非常麻烦,所有曾经从事UI工作的人都清楚每次都要千辛万苦才能找到要修改的UI。

当然,SDK重要的部分是控制库。由于Flutter的定位是Android和iOS开发,因此我们可以选择使用Material(Google Android)或Cupertino(Apple iOS)控件集。这是否意味着当应用程序部署到Android或iOS手机上时会切换外观,让两者看起来都很像是原生的?并非如此。你可以随便使用哪个库,也可以同时使用两者,但是并没有统一的切换UI的功能。当然,你可以手动实现,我并不是说不建议这种做法。但请记住这种功能需要管理两组不同的布局控件,很快就会乱成一锅粥,因此应当谨慎地采用这种方法。

在默认情况下,Flutter中的所有内容都是小部件(widget)。如果你有使用Angular 2+的经验,那么可以认为wdiget就是更强大的组件,而且应该是一个非常熟悉的概念。在默认情况下,这种基本类型包含一个定义外观的build方法,而且还可以根据传递的参数和上下文自定义外观。小部件可以是无状态的也可以是有状态的。无状态小部件大部分都是静态的,不会在生命周期中发生任何明显的变化。另一方面,有状态的小部件在每次触发时都会被构建(例如,当监视的变量发生变化、用户执行单击等特定的操作)。

Flutter是响应式编程(类似于React),这意味着没有默认的持续刷新循环(像Angular那样)。取而代之的是,一旦执行了关键操作,UI或其一部分(比如其中一个小部件)就会根据状态的变化重新绘制。

我曾提过,Dart为处理UI进行了大幅优化以,但这意味着什么?在Flutter中,经过优化后的Dart支持丰富的集合处理、基于隔离的并发以及future的async-await。基本上这种SDK面向的应用程序都是构建业务,而不是游戏。尽管我们不能假设人们不会尝试使用Flutter制作游戏,甚至现在已经出现了2D游戏引擎。但我想说的是,这种应用程序的模式似乎非常适合这组特定的功能,而这也是我决定探索的角度。

风险

尽管上述一切听起来很美好,但也有一些弊端。

首先,Flutter仍然是一个处于起步阶段的SDK。虽然从它的年龄上来看属于正常,但应该注意的是,alpha版于2017年5月发布,而1.0版本到于2018年12月才发布。这意味着在撰写本文之际,Flutter仅有一年的历史。这有什么后果?Flutter的社区虽然已具规模,但仍不能与当前的主流技术相提并论。这会影响我们寻找一些常见问题的解决方案,而且可能会经历多次失败,需要付出额外的努力,并仔细阅读规范。但是,Flutter的文档很健全,并且社区在不断发展,因此我们可以认为Flutter在发展中,没有明显的缺陷。

其次,Flutter和Dart都来自Google(这既可以看作缺点,也可以看作是优点)。好的方面是Google是科技巨头,如果他们想维护,那么资源和人力都很充足。但缺点是,虽然众所周知Google会推出非常实用的技术和服务,但也有可能随时将其淘汰出局。Flutter也面临这样的风险,但近期内不太可能会发生,甚至在未来几年也不会。因此,虽然这是一种风险,但是再说一次,任何新技术都有同样的风险,而且每种技术都有这样的经历。

使用哪些工具?

我们可以使用最常见的编程IDE(Android Studi、IntelliJ IDEA,甚至还有支持Flutter的Visual Studio Code插件)来开发Flutter,这意味着大多数开发人员都不必离开熟知的环境。就我而言,最近我一直在从事面向Web的工作,所以我选择了VS Code,但这不会对开发造成任何影响,因为文本文件说到底仍然只是文本文件。我选择的平台是Android(选择这个平台的原因是因为我既没有iPhone、MacBook,也没有iMac),因此看起来无论如何我都会安装Android Studio,因为Android Studio提供了虚拟机。

除了IDE之外,还有Flutter/Dart DevTools,这是一个套件,用于监视应用程序的性能,此外还有一些调试工具,例如Flutter查看器,类似于WebTools。在调查应用程序的性能瓶颈时,实时资源监控器非常实用,还有层级查看器可以找出困扰着许多应用程序和网站UI的冗余嵌套。

入门:“Hello World”

下面我们来编写一个管理保单的移动应用程序,还有比这这更令人兴奋的事儿吗?请务必注意,我可能会尝试以不同的方式来开发有些功能,所以可能会导致代码不一致。这个应用程序包含了一些解决常见问题的想法和示例,孰优孰劣留给个人评判。

应用的简单概述:

  • “主页”画面显示已购买的保单摘要

  • 创建一个保单

  • 通过向导完成保单创建

  • 保单可以是不同的类型

  • 保险主题可以是不同的类型

  • 用户需要账号(不能匿名使用)

  • 该应用程序是一个“轻量级客户端”——所有字典、数据和操作都存储在服务器端

  • 请求/响应主体格式为JSON

我们通过Mockoon模拟API,IDE的话我选用VS Code,设备则由Android模拟器提供(我选择了Nexus 6 API 28)。首先,我根据Flutter官方网站上提供的官方指南创建了一个空白应用,随后创建Flutter项目的准系统。就我个人而言,我创建了如图1所示的结构。完整的应用代码请点击这里(https://github.com/asc-lab/personal-insurance-flutter-poc),我建议你参照着本文一起看。

[图1] 初始阶段的项目

查看项目的基础

pubspec.yaml文件包含了项目的依赖项、资源文件和版本号,非常简单明了。此外,该文档还包含了许多说明,但我们不会修改这些说明,至少不会经常都修改。对我们来说最重要的是lib文件夹,因为其中保存了应用程序的起始文件main.dart文件,以及其中的main方法。这是应用程序的入口点,任何代码都不应超出该点。好了,下面该搭脚手架了。

主页是应用程序的默认页面,也是默认的路由。我们将在主页展示一系列的保单。因此,通过我们的api获取字典肯定很合适。我构建了一个调用API服务的单例服务,并在应用程序启动之前就获取字典数据,这样在应用程序的任何位置都可以使用这些数据。这个字典名叫CommonData,而字典的API服务是DictionariesService。二者都位于lib/services文件夹中。我还添加了一个通用的帮助服务(名叫Helper),提供默认填充、常用转换等功能。

[图2] CommonData

CommonData是一个单例,它有一个内部构造函数,该构造函数将其唯一的实例存储在自己的某个静态字段中。CommonData类定义不会在应用程序的其他任何地方使用,仅在这个文件中用于声明commonData实例。DictionariesService.get方法会返回Future<DictionariesService>,它实质上实是一个promise。这意味着我们可以使用await等它返回结果,并在一切准备就绪后继续执行initialize,或者使用.then(…)并尽早返回。我们希望initialize在收到响应后完成,因此我们使用await。稍后我们将介绍DictionaryService.get的实现。

经过一番研究后,我发现在绘制UI之前运行commonData.initialize非常简单,因此我们将其放到main中(如图3所示)。

[图3] 在运行应用之前初始化commonData

这样一来,无论我们在应用任何位置,都可以确信commonData已被初始化,因为应用本身都是在initialize完成后执行的。这样的解决方案在许多情况下都很管用,例如服务器存储的应用程序配置文件或主题、数据暂存、应用程序设置等。对于异步操作,我们应该在主页画面上进行处理,因为我们可以在主页画面上显示加载进度条。这样可以避免在应用启动时用户看到空白的屏幕,然后怀疑应用程序是不是崩溃了。因此,如果我们必须在应用程序正常启动之前做点什么,那么最好是执行可预测、可忽略执行时间的操作,或者创建一个单独的“加载”画面,并显示一些动画和明确的“加载”消息,让用户放心地等待操作执行,并在完成操作后返回主页。这种“尴尬的预加载”就留在这里作为UX的反面教材吧。

下面,让我们来看看main下方的MyApp类。它的主体主要是重写build(BuildContext)方法,该方法会在每次重绘MyApp小部件时调用。我们的应用有多个画面:主页和创建保单向导的5个步骤(保单类型、产品、覆盖范围、投保人和投保对象),因此我对相关主题进行了仔细研究(如图4所示)。

[图4] Flutter应用程序的导航研究

在Flutter中,导航称为“路由”。我已经根据教程创建了一些路由(如图5所示)。默认的初始路由(MyHomePage小部件)和五个向导步骤。我们是否需要访问构建上下文尚有待观察,但先放在这里总没有坏处。

[图5] Flutter应用中基本的路由

Material Design中的Flutter

值得一提的是,由于我们的应用使用了Material控件集,并且是MaterialApp实例,因此我们可以按照Material Design原则快速修改外观。ThemeData类包含了“material design主题的颜色和版式数据”。在应用程序中可以通过静态方法Theme.of(BuildContext)访问ThemeData,改变它的各种属性,以更改主题提供的默认值。现在,我们只需设置primarySwatch(应用程序的主色调及各种明度的颜色)和accentColor(也是各种明度的颜色组合,是应用的辅助色)。

如果我们使用主题的默认值和/或生成的值(我们应尽力做到这一点),则最终的UI看上去应该不会太差。如果我们不想使用默认的颜色,则可以自定义颜色(如图6所示)。不过,这需要进行大量的工作(除非客户提供了样式指导),而且我不想破坏审美,因此就按照简单的方法来吧。网上有无数的材质色样生成器,如果你想提供“基本”的色调,则可以生成一个。此外,还有一个errorColor设置,但是作为一个涉猎UI/UX领域多年的人,我建议你谨慎使用这个设置,因为标准的红色是错误指示的行业标准。即便颜色方案允许修改,也应该尽量避免,最多只是稍微修改一下明度即可。

这个过程也可以用来测试“热重载”:尝试更改主题颜色,保存,然后就能立即看到应用的变化。这个功能我非常满意。

[图6] 自定义颜色的示例

主页

主页基本上就是一个列表,里面展示了每个保单,每个列表项可以展开显示保单的详细信息,另外还有一个创建新保单的选项。因此,每个列表项应该是有状态的,因为列表项的外观会发生变化大,但是整个页面可以是无状态的。主页显示了一个可变长度的列表,但是在其生命周期内,其中的元素和值不会发生变化。请注意,如果我们没有将每个列表项分成独立的小部件(而是在一个类中处理所有内容),那么页面就必须是有状态的。

[图7] MyHomePage 数据初始化

让我们从路由(图7)中的数据开始。每次导航到’/’时都会执行此处的逻辑。在这种情况下,这种做法很方便,因为每次我们显示主页画面时,都会有最新的用户账号数据和已创建的保单。这样一来,我们就解决了将来会遇到的问题:完成导向后如何刷新主页面。我们只需要导航回去即可。

在MyHomePage(homepage.dart)内,你可以看到一些UI定义。页面的根名称为Scaffold,它负责设置应用程序栏、操作按钮、文档主体和其他各种选项,实际上这就是通用的移动应用模板。未定义的部分会被省略该。这里的appBar是最小设置,有一个floatActionButton来启动新的保单向导,backgroundColor已与当前主题的背景色挂钩(如果我们想改变颜色,则需要保持一致性),当然还有最主要的主体。

如前所述,这些保单被包装在一个Future中,表示它们还不能传递给ListView。这就是FutureBuilder<>的用途:实际上,它是一个小部件,可以根据Future的内部状态返回内容。我们可以使用快照(AsyncSnapshot)变量,根据Future是否已完成或仍在进行中,或者是否包含错误等,返回不同的窗口小部件。

对于我们来说,如果已完成则返回一个ListView,否则返回一个加载指示器——非常标准的东西。最好将所有可能的错误处理包装到Helper类中的某个通用方法中,Helper类可以接受snapshot.connectionState并输出一些通用的错误信息。解决Future中的错误有很多方法,但这里为了简洁起见,我没有使用这些方法。因此,一个Future只能是已完成或正在加载两种状态之一。

[图8] FutureBuilder

再来看看HomepageTile小部件。这是我们的第一个有状态的UI。每个有状态的小部件都包含小部件声明(图9)及其状态,而状态才是最神奇的部分。

[图9] 有状态的小部件

小部件的UI在状态中通过build方法定义。因此,每次调用setState(fn),框架都会重新构建,并使用新的属性值重新执行build(BuildContext)方法。此处,我使用了_expanded字段值作为条件,来决定应该返回_buildMiniTile还是更详细的_buildMaxiTile小部件。当然,这可能只是一个简单的条件赋值问题,但是我们可以利用AnimatedCrossFade小部件来美化。

它的功能正如其名:根据crossFadeState(图10)让两个子部件交叉淡入淡出。由于每次setState调用都会重新构建小部件,因此在两个以上的状态之间进行切换也是可能的,但这种用法非常罕见,因为通过特定数量的点击进入某个状态听起来有点像在戏弄用户或玩捉迷藏游戏。除非有强烈的视觉暗示,否则不要这样做。

[图10] AnimatedCrossFade

现在我们知道了怎样创建主页,并利用通用的列表项来显示用户的保单。接下来演示一下怎样给应用程序提供Mockoon API中的数据。我们打开DictionariesService(图11)。

[图11] DictionariesService

可以看到,get函数标记为async,意思是它的返回值会包裹在Future<>中,采用类似于promise的处理方式。http客户端会异步执行命令,然后提供响应结果、状态码等。紧接着我们将JSON(其类型默认为Map<String, dynamic>)映射为DTO对象。由于这些是字典,所以我为它们创建了map,这样就不需要在显示某个代码对应的名称时遍历所有元素了(只需这样写即可:commonData.maps[DictCode.PRODUCT_TYPE][_policy.type])。

接下来看看DTO。将json转成对象并没有公认的方法,但幸运的是我们可以利用很多插件。我这里使用了json_annotation(https://pub.dev/packages/json_annotation),用它来监视启动后(flutter packages pub run build_runner watch)就会寻找 @JsonSerializable标记并创建映射函数,如图12~13所示。

[图12] policy.dart - DTO类

[图13] policy.g.dart - 由json_annotation生成

这可以大幅简化工作,并提供非常方便的方式将类映射到JSON。

向导

每个成功的商业应用必不可少的两部分就是表单和验证。我们来看看我们要做的功能,以及保单向导的代码。前两步(1_newPolicyType,2_newPolicyProduct)都是随处可见的、非常标准的东西,这里就不再赘述了。如果你想看看如何利用异步执行计算来填充表单,那么可以查看3_newPolicyCovers步骤,它包含了一个假的保费计算的实现。

app表单

表单的定义非常标准——首先定义一个Form对象,在预先生成的GlobalKey<FormState>键中进行处理,然后定义元素,如4_newPolicyYou.dart文件和图14所示。

[图14] 4_newPolicyYou.dart——非常直观的表单定义。注意这里使用了Helper来减少代码。

表单可以通过多种方式与数据交互,所以可以按照开发者的喜好来设计。如果需要伪双向绑定行为,可以将onChange处理函数中的值持久化到setState中。但是也可以仅使用onSaved,在表单完整之后再持久化数据。我决定采用后一种方法。Step4Builder类(图15)中包含了向导的序列——如果表单合法,则保存后继续。向表单中注入数据则采用了很简单的方法:由于我们从模型传递值给表单(processData)中相应控件的initialValue,因此每次setState操作的时候控件都会被更新。

这就是为何我们只需要填充模型的字段(processData.setOwnerFromAccount),然后使用this._formKey..currentState.reset重置表单即可,这样就可以重新计算字段的初始值——直接从模型中获取值。但是为什么要重置表单呢?因为这样可以保证,只要我们不持久化表单中的值,我们在setOwnerFromAccount中没有填充的字段就可以获得默认值(这些默认值也存在于模型中)。

这只是策略之一。在不同的情况下我们可能会选择其他方法,但要注意的是,我们并不需要一定采用某种方法。

[图15] Step4Builder - 如果表单合法,则保存并转向下一步。非常干净。

动态表单布局的实现跟传统的js/html没什么太大区别。在向导最后一步的5_newPolicySubject.dart中,我们应该创建保单投保对象的数据,因此需要根据数据类型(汽车、人或者蜥蜴等)来采用不同的表单。实现方法是在不同的小窗体中定义不同的字段集合,然后根据前一步的选择来显示合适的那个。应用程序中仅实现了一个类型(reptileObject.dart),但只需在build方法中检查一下就很容易实现添加其他的类型(图16)。

[图16] 5_newPolicySubject.dart:我只想为我的宠物蜥蜴投保,因此唯一的表单定义就是Reptile对象,但我们当然可以通过在子属性中插入if语句来显示正确的表单。

现在,我们有文本框和下拉菜单,下一步该编写日期控件了——其实控件并不存在。如果你开发过移动应用,也许这听上去有些奇怪,但是如果仔细考虑一下就会发现这完全合理。最好的方案永远是使用系统提供的input(例如,我们不需要定义键盘控件,只需要使用系统提供的即可),而每个移动系统都提供了自己的日期控件,一般表现为日历的形式。因此我们的“日期输入”仅仅是一个只读的TextFormField,当我们触摸该控件时,它会要求系统提供值。前面提到的reptileObject.dart文件就包含了一个例子(图17-18)。

图17-18:reptileObject.dart - TextFormField的责任非常少,只需要告诉系统用户需要输入一个日期,然后显示该动作的结果即可。我们定义了一个onTap处理函数,来拦截针对控件的交互,然后显示系统的datepicker。由于这是一个异步的动作(用户可以花很长时间来选择日期),因此整个方法必须标记为异步。

验证——使用errorColor

现在表单已经完成了,我们需要提供一些基本的数据验证。规则非常简单:每个表单控件有一个“validator”属性,它接受一个函数,函数的输入就是值,输出是一个字符串。如果输出非空,则输出的内容就表示验证错误消息,显示在适当的区域。图19演示了一个组合验证(两个条件、两条消息)的简单示例。

图19:简单的验证 - 如果Validations.required返回错误消息,则返回该消息。否则检查输入是否为有效的邮件地址。如果不是,则返回自定义的错误消息。

到这里一切都很顺利,但如果我们需要进行异步验证(比如检查用户名是否已存在)该怎么办?嗯……很难。Flutter不支持在验证中使用Future<>,而且应该永远不会支持,据说这样会破坏同步验证,而且由于这些原因(https://github.com/flutter/flutter/issues/9688)混合两种验证方式并不是很好的UI实践。

即使接受这个现实,我们也会遇到必须进行服务器端验证的情况,那么唯一的选择就是将海量的数据加载到设备上。不过幸运的是,有一个广为人知的非常简单的技巧。只需在验证器中执行调用然后切换一个局部标志。如果标志被设置,则不显示任何验证信息。当验证结束后将验证结果保存到某个局部变量中,然后切换该标志,然后手动触发表单的验证。这样,第一次验证触发时不会显示任何信息(或者可以显示“请稍候……”表示动作正在执行),第二次验证将验证信息改成动作的结果(需要覆盖“请稍候……”)。

因此,尽管我们可以这样进行异步验证,但还是希望SDK能提供支持。这样可行,但应该更干净一些。

不管如何,现在应用程序可以运行了,而且开发这个程序根本没有花太多时间。我们考虑了实现商业应用的绝大多数基本问题,而且并没有什么太难的地方。所以可以认为这个应用程序是成功的。我们现在可以去掉那个反面教材,清理下代码,与后台结合,然后在收到客户反馈后重新修改。

我们来看一看这个应用程序:

[图] 政策主题页面

最后的感想

那么,我们应该使用Flutter来开发移动应用吗?我认为需要考虑几个问题才能做出判断,不同的人可能会得出不同结果。

如果你是第一次开发此类移动应用,我会推荐你使用。Flutter的学习曲线非常平缓,也不需要任何前提知识。通过教程和各种文档可以很容易地判断哪些场景下应该使用什么,而采用的工具完全可以自行决定。在学习一个存在了许多年的框架时,一些太过明显的实践人们就不会再谈起,导致这些实践很难学到。由于Flutter相对比较新,因此没有什么显而易见的问题,因此也没有那些被埋在各种新功能下的人尽皆知的技巧。相反,对于经验丰富的移动开发者,对待Flutter的态度应该与其他新技术一样。在创建有很多功能的高级应用时,如果你对某个技术有经验,那么应用程序越大,该技术的优势就越大。但是,如果你要开发一个很小的应用,那么Flutter是快速开发中的无价之宝。

Flutter的社区依然在成长。社区还不是很大,但也不是太小。关于这一点大家的意见可能不一样,但我认为当前的社区大小已经足够支持小型到中型的开发。用户基础越大,边缘情况就被研究得越透彻,也就越容易找到帮助,所以只要社区依然在稳健成长,对大型项目的支持也会越来越完备,风险也会越来越小。

现在有许多Flutter开发的应用,因此已经不是小众框架了。从官方网站上可以看到,不仅Google在用,许多大牌公司也在用。这表明Flutter的技术支持计划在向好的方向发展,因此值得一试。考虑到该技术依然很新,因此这些公司很可能需要在推出应用程序之前进行一些研究,但研究之后依然选择了Flutter,所以证明Flutter可能已没有太大风险。只要有足够的时间,Flutter应该能够成为开发移动应用的首选。

众所周知,市场变化很快,但这并不能阻止我们探索新事物。而且毕竟看来Flutter值得我们去尝试。

原文链接:

https://altkomsoftware.pl/blog/flutter-dart-quickly-build-mobile-app-without-losing-much-hair/

本文为CSDN翻译文章,转载请注明出处。游戏网

相关下载

玩家评论

搞笑GIF:你的头发没了,可能就是写字的结果_弟弟

当年的老公太帅了,怎么在我手里就变丑了那 但凡你多喝点奶,身高也不至于马上被一颗青菜超越! 狗子,你这个造型也实在是太酷了。票到底是谁给你画的呀? 小详情>>

阅读: 0
日期: 2020-03-15
搞笑GIF:头发撩开的时候,我被吓得一哆嗦_买手机

哥们儿,恭喜你,下次还是你结婚 一只死活不肯打针的大金毛! 看吧!我都说了一点都不疼! 这操作厉害了! 头发撩开的时候,我被吓得一哆嗦 对于美女我是没详情>>

阅读: 0
日期: 2020-03-15
妈妈的假发飘进我盛汤的碗里算吗_头发

这里有好看的皮囊和有趣的灵魂,只准笑不准哭 高中同学漂的黄头发,在学校只能戴假发,有一次体测跑步把头发甩飞了,把体育老师吓得以为我同学把头跑飞了 这个经详情>>

阅读: 2
日期: 2020-03-12
昔日天后凌晨直播,头发凌乱面露憔悴,母亲去世给她留下10亿遗产_萧亚轩

原标题:昔日天后凌晨直播,头发凌乱面露憔悴,母亲去世给她留下10亿遗产 3月12日零点,昔日歌坛天后萧亚轩在社交平台直播宣传新歌。镜头中的萧亚轩头发详情>>

阅读: 1
日期: 2020-03-12
当灿烈入伍的时候头发是不是这个样子的....有点秃然??_App

灿烈入伍的时候是不是这个样子的....? 爱丽们别闹了!!没有这么光!!顶多就是个寸头怎么把我们灿烈变成卤蛋了哈哈哈哈哈哈哈这个真的有被笑到,实在是太秃然了但是帅详情>>

阅读: 4
日期: 2020-03-10
搞笑GIF趣图:一个女人撩头发都受不了,何况是三个一起了_睡眠

一个女人撩头发都受不了,何况是三个一起了 车怎么就自己跑了还掉进河里了! 你以为我是真对你好啊!我是要坑你啊! 你这太厉害了!练习的竟然是铁头功啊! 我详情>>

阅读: 2
日期: 2020-03-04
开心一刻笑话:陪女友去做了个头发,完事后顺便去逛街_大李

1.上个星期和老婆吵架,一气之下她把所有东西都摔了而且回了娘家。我才不去接她,我得想个办法让她自己回来于是,我给她卡里打了5万。第一天还是没有回家,是不是嫌少详情>>

阅读: 4
日期: 2020-03-01
同穿白色连衣裙,当杨幂遇上王鸥,这就叫神仙过招_头发

原标题:同穿白色连衣裙,当杨幂遇上王鸥,这就叫神仙过招 一条小白裙,是每个有少女心的女生衣橱里必备的款式。 白色连衣裙总是自带仙气,好似云朵那样洁详情>>

阅读: 5
日期: 2020-02-29
天涯明月刀手游头发染色多少钱头发染色价格介绍

天涯明月刀手游中除了捏脸还能给头发染色,那么游戏中头发染色多少钱呢?下面小编给大家带来了天涯明月刀手游头发染色价格介绍,一起来看看吧。头发染色多少钱玩家可以消耗10个染详情>>

阅读: 6
日期: 2020-02-24
因为一根头发乱飘谢娜邀网友到自家擦地板

原标题:因为一根头发乱飘 谢娜邀网友到自家擦地板 因为一根头发乱飘 谢娜邀网友到自家擦地板游戏网 详情>>

阅读: 6
日期: 2020-02-12
大锤哥兑现Flag剃光头,头发剃到一半捂脸痛哭,自嘲:真的太丑了

苦瓜原创,翻版必究! 《苦瓜电竞》--让你体验不一样的电竞主播圈! 作为如今大热的手游,王者荣耀可是成就了太多人,从职业选手到专业主播,这些人都是很真心的感详情>>

阅读: 11
日期: 2020-02-09
油画肖像作品,头发的配色秘诀_颜色

原标题:油画肖像作品,头发的配色秘诀 无论是追求古典的写实主义还是印象派肖像,一些特定的技巧将改善头发效果。 画头发小建议: 1、头发外轮廓,与背详情>>

阅读: 12
日期: 2020-02-07
搞笑GIF趣图:兄弟,跟老婆吵架而已,何必要染绿色头发呢!_老外

绿布特效,你欺骗了多少老实人 没点精神病都不好意思说自己是书法家! 这货待遇也太好了,人不如狗 妹子,没想到你刀上功夫了得啊 兄弟,你这媳妇在哪找的?详情>>

阅读: 6
日期: 2020-01-17
木北造型:8月女孩发型设计有哪些选择三款时尚小短发提升气质和颜值_头发

原标题:木北造型:8月女孩发型设计有哪些选择 三款时尚小短发提升气质和颜值 如果你是一个发型控,那么你绝对不要错过接下来的几篇文章。在这里我会介详情>>

阅读: 8
日期: 2020-01-17
美女一袭粉色连衣裙,尽显迷人身材,风吹头发更飒了_穿着

原标题:美女一袭粉色连衣裙,尽显迷人身材,风吹头发更飒了 感谢您百忙之中抽空出来阅读小编的文章,祝您每天都笑容满面,心想事成,家庭美满!下面开始送上今详情>>

阅读: 8
日期: 2020-01-15
贾静雯最新写真曝光,头发向后撩又美又飒,尽显成熟女人魅力_孩子

原标题:贾静雯最新写真曝光,头发向后撩又美又飒,尽显成熟女人魅力 如今娱乐圈涌进来越来越多的艺人,门槛不断下降,看着热度很高,但其实未必有什么拿得出详情>>

阅读: 4
日期: 2019-12-31
泫雅的爆炸头是新晋流行?还是温柔的长卷发最受欢迎_头发

原标题:泫雅的爆炸头是新晋流行? 还是温柔的长卷发最受欢迎 谁说明星就不会有造型失手的时候?不久前自带热搜体质的泫雅又带着她的爆炸头来了。 不详情>>

阅读: 6
日期: 2019-12-30
忽胖忽瘦脸圆腿粗,清冷挂爱豆难逃岁月魔咒?_头发

原标题:忽胖忽瘦脸圆腿粗,清冷挂爱豆难逃岁月魔咒? 说起折腾头发,怎么也少不了爱豆们。 仿佛头发就是块画布,说染就染,说烫就烫。 赤橙黄绿青蓝紫一天详情>>

阅读: 7
日期: 2019-12-28
蒋欣头发越剪越短,90斤的面容显玲珑娇俏,穿格纹西装中性风十足_短发

原标题:蒋欣头发越剪越短,90斤的面容显玲珑娇俏,穿格纹西装中性风十足 小密语录:不剪短发你永远不知道自己原来这么有范,穿上西装更是时髦大气,不过要想详情>>

阅读: 7
日期: 2019-12-27
娱乐圈20位男星的18岁徐峥、张卫健有头发太帅了!

【导读】18岁是一个人最好年纪,虽然可能还没有功成名就,但是拥有无限的精力和宽广的未来。今天我们来盘点下那些男明星十八岁的时候在做什么,长什么样子!--> 详情>>

阅读: 6
日期: 2019-12-25
搞笑GIF:上初中那会,我短头发,我们班主任就说我:_信号

带老婆来这里游玩的,都是想看别人老婆的 鸡头稳定性测试系统 ???? 哥,是不是有种冲浪的感觉 刀削面一条街 大叔:我也想低调,但是实力不允许啊! 哇~~详情>>

阅读: 6
日期: 2019-12-20
73岁侯耀华独自现身批发市场,穿着花哨搂着女粉丝合影特别潮_头发

原标题:73岁侯耀华独自现身批发市场,穿着花哨搂着女粉丝合影特别潮 近日,有网友在深圳某批发市场偶遇了独自现身的侯耀华。从曝光的侯耀华和粉丝的合详情>>

阅读: 8
日期: 2019-12-18
有了这5款简易发型,这个冬季你再也不用把头发藏在帽子内!_hair

原标题:有了这5款简易发型,这个冬季你再也不用把头发藏在帽子内! 对于女生来说,其中一种发明得很好的时尚配件应该就是帽子吧!帽子款式多变,不同类型的详情>>

阅读: 9
日期: 2019-12-18
“刺死辱母者”于欢母亲出狱:49岁头发全白

原标题:“刺死辱母者”于欢母亲出狱:49岁头发全白 据媒体报道,2016年4月14日,因不堪母亲苏银霞受辱,时年22岁的于欢将水果刀刺向了讨债人。 2017年2月,详情>>

阅读: 8
日期: 2019-12-16
于欢母亲出狱:49岁头发全白,自称拖累儿子,她怎如此“煎熬”?

原标题:于欢母亲出狱:49岁头发全白,自称拖累儿子,她怎如此“煎熬”? 三年前的“于欢案”,随着于欢母亲苏银霞的出狱,基本上归于“最好的结局”。不过,从详情>>

阅读: 15
日期: 2019-12-16
小S花式秀恩爱,老公亲手帮其染发_头发

原标题:小S花式秀恩爱,老公亲手帮其染发 南都讯 记者麻乐小S做洗发水代言人多年,一头乌发短发成其经典形象,孰料艺人造型也非总是百万造型师打造,头发详情>>

阅读: 6
日期: 2019-12-13
靠模仿泫雅出圈的女明星遇到本尊,同框合照竟然差距这么大_头发

原标题:靠模仿泫雅出圈的女明星遇到本尊,同框合照竟然差距这么大 前几天泫雅现身上海营业了,一身银色亮片装性感摩登,状态非常好。 很多网红在微博上详情>>

阅读: 7
日期: 2019-12-07
这台风简直太绝了,难怪6岁就获选美冠军,连头发也梳成大人模样_Freya

原标题:这台风简直太绝了,难怪6岁就获选美冠军,连头发也梳成大人模样 近日,泰国一名年仅6岁的小女孩引起了网友们的关注,因为她获得了Mister and Misst详情>>

阅读: 12
日期: 2019-11-30
搞笑GIF趣图:好头发,好女人,原来还是一位大美人! _段子

好头发,好女人,原来还是一位大美人! 来自大爷与大妈的巅峰对决,你们觉得他们两个人谁会取得最终的胜利? 这是不是脑白金奶奶的原型啊? 美女想要感受详情>>

阅读: 6
日期: 2019-11-27
头皮清清爽爽、头发根根竖起,全靠这坨泡沫_成分

原标题:头皮清清爽爽、头发根根竖起,全靠这坨泡沫 小编最近发现了一款氨基酸无硅洗发水,第一次用就惊呆了: 泡沫厚实到可以挤着玩 它竟然一遇水就“详情>>

阅读: 15
日期: 2019-11-25
JK美少女,太帅太有气势啦,头发飘起来特别有感觉_Ameng

原标题:JK美少女,太帅太有气势啦,头发飘起来特别有感觉 【二次元cosplay大全(erciyuancosplay),小伙伴们,未经coser许可禁止转载到其他地方哦,原文转发到详情>>

阅读: 6
日期: 2019-11-22
《犬夜叉》中唯一因重度脱发而自卑的妖怪,妖生目标“长头发”!_满天

原标题:《犬夜叉》中唯一因重度脱发而自卑的妖怪,妖生目标“长头发”! 《犬夜叉》是90时期最为经典的动漫作品之一,承载了无数90后观众的童年。虽然随详情>>

阅读: 3
日期: 2019-11-20
钟楚曦挑战杨幂同款“复古蜂窝头”,一个像奶奶一个太时尚!_头发

原标题:钟楚曦挑战杨幂同款“复古蜂窝头”,一个像奶奶一个太时尚! 钟楚曦给红秀拍的大片大家看了吗?区花真的是有被惊艳到,服装、造型、身材完全没得挑详情>>

阅读: 9
日期: 2019-11-20
女人出门头发就这样扎,男人看得走不动路!_短发

长头发的姑娘别急着剪短发,剪了多可惜啊,好多人都是剪了短发就后悔,害怕后悔还不如学习下丸子头的扎法,这个季节扎个丸子头清爽极了!比任何发型都漂亮! 这么详情>>

阅读: 6
日期: 2019-11-18
相恋18载终不敌分手噩梦,女歌姬恢复单身反倒面色红润。_头发

原标题:相恋18载终不敌分手噩梦,女歌姬恢复单身反倒面色红润。 80和90后关于青春初恋的记忆,总是绕不开疼痛青春鼻祖安妮宝贝那句“海藻般浓密的长发详情>>

阅读: 7
日期: 2019-11-17
欢笑集锦:老子是抢手机的,再跑一条街就可以甩掉你老婆了_头发

1晚饭前小侄女要我带她到楼下买东西吃,我不去。小侄女问:“到底去不去?”我说:“不去。”小侄女说:“信不信我让奶奶打你?”说完她的眼睛一动不动地看着我,慢慢的慢慢详情>>

阅读: 7
日期: 2019-11-15
精彩推荐