Flutter開發(fā)技術(shù)與分享(二) —— Flutter 入門(一)

版本記錄

版本號 時間
V1.0 2019.11.03 星期日

前言

Flutter是谷歌的移動UI框架,可以快速在iOS和Android上構(gòu)建高質(zhì)量的原生用戶界面。 Flutter可以與現(xiàn)有的代碼一起工作。在全世界,F(xiàn)lutter正在被越來越多的開發(fā)者和組織使用,并且Flutter是完全免費、開源的。目前公司的部分模塊就是在使用Flutter進(jìn)行開發(fā)。感興趣的可以看下面幾篇文章。
1. Flutter開發(fā)技術(shù)與分享(一) —— 基本概覽(一)

開始

首先看下主要內(nèi)容

通過使用VS Code編寫跨平臺應(yīng)用程序,深入研究Flutter框架,以在單個代碼庫中構(gòu)建iOSAndroid應(yīng)用程序。下面是翻譯文章的地址

然后看下寫作環(huán)境

寫作環(huán)境:Dart 2, Flutter 1.7, VS Code

自十年前iOSAndroid平臺風(fēng)起云涌以來,跨平臺開發(fā)一直是整個移動開發(fā)領(lǐng)域的目標(biāo)。 能夠為iOS和Android編寫一個應(yīng)用程序的功能可以為您的公司和團(tuán)隊節(jié)省大量時間和精力。

多年來,已經(jīng)發(fā)布了用于跨平臺開發(fā)的各種工具,包括基于Web的工具(例如AdobePhoneGap),強大的框架(例如MicrosoftXamarin)以及更新的工具(例如FacebookReact Native)。 每個工具集都有其優(yōu)缺點,并且在移動行業(yè)中獲得了不同程度的成功。

進(jìn)入跨平臺領(lǐng)域的最新框架是GoogleFlutter。 Flutter在兩個平臺上均具有快速的開發(fā)周期,快速的UI呈現(xiàn),獨特的UI設(shè)計以及本機應(yīng)用程序性能。


Introduction to Flutter

Flutter應(yīng)用程序是使用Dart編程語言編寫的,該語言最初也來自Google,現(xiàn)在是ECMA標(biāo)準(zhǔn)。 Dart與其他現(xiàn)代語言(例如KotlinSwift)具有許多相同的功能,并且可以轉(zhuǎn)編譯為JavaScript代碼。

作為跨平臺框架,Flutter最類似于React Native,因為Flutter允許響應(yīng)式和聲明式編程風(fēng)格。但是,與React Native不同,Flutter不需要使用Javascript橋接,這可以縮短應(yīng)用程序的啟動時間和整體性能。 Dart通過使用Ahead-Of-TimeAOT編譯來實現(xiàn)此目的。

Dart的另一個獨特之處在于它還可以使用Just-In-Time or JIT編譯。 FlutterJIT編譯通過允許熱重裝(hot reload)功能在開發(fā)過程中刷新UI而無需全新的構(gòu)建,從而改善了開發(fā)工作流程。

正如您將在本教程中看到的那樣,Flutter框架主要圍繞widgets的概念構(gòu)建。在Flutter中,widgets不僅用于應(yīng)用程序的視圖,而且還用于整個屏幕甚至應(yīng)用程序本身。

除了跨平臺的iOS和Android開發(fā)之外,學(xué)習(xí)Flutter還可以讓您搶先開發(fā)Fuchsia平臺,Fuchsia平臺目前是Google開發(fā)的實驗性操作系統(tǒng)。

在本教程中,您將構(gòu)建一個Flutter應(yīng)用程序,該應(yīng)用程序?qū)⒉樵?em>GitHub API中的GitHub組織中的團(tuán)隊成員,并在可滾動列表中顯示團(tuán)隊成員信息:

您可以同時使用iOS模擬器或Android模擬器來開發(fā)應(yīng)用程序!

在構(gòu)建應(yīng)用程序時,您將了解有關(guān)Flutter的以下知識:

  • Setting up your development environment
  • Creating a new project
  • Hot reload
  • Importing files and packages
  • Using widgets and creating your own
  • Making network calls
  • Showing items in a list
  • Adding an app theme

順帶著你也會學(xué)習(xí)一點關(guān)于Dart的知識。


Setting up your development environment

Flutter開發(fā)可以在macOSLinuxWindows上完成。 盡管您可以將任何編輯器與Flutter工具鏈一起使用,但是有 IntelliJ IDEAAndroid StudioVisual Studio CodeIDE插件可以簡化開發(fā)周期。 在本教程中,我們將使用VS Code

在此處here可以找到有關(guān)使用Flutter框架設(shè)置開發(fā)機器的說明。基本步驟因平臺而異,但大多數(shù)情況是:

  • 1) 下載適用于您開發(fā)計算機操作系統(tǒng)的安裝包,以獲取Flutter SDK的最新穩(wěn)定版本
  • 2) 將安裝包解壓縮到所需位置
  • 3) 將flutter工具添加到您的路徑
  • 4) 運行flutter doctor命令,該命令將安裝Flutter框架(包括Dart)并提醒您任何缺少的依賴項
  • 5) 安裝缺少的依賴項
  • 6) 使用Flutter插件/擴展程序設(shè)置您的IDE
  • 7) 測試驅(qū)動一個應(yīng)用

Flutter網(wǎng)站上提供的說明做得很好,可以讓您輕松地在所選平臺上設(shè)置開發(fā)環(huán)境。本教程的其余部分假定您已經(jīng)為Flutter開發(fā)設(shè)置了VS Code,并且已經(jīng)解決了flutter doctor發(fā)現(xiàn)的所有問題。

如果您使用的是Android Studio,那么您也應(yīng)該能夠很好地遵循。您還需要運行iOS模擬器,Android模擬器,或者已設(shè)置預(yù)配置的iOS設(shè)備或Android設(shè)備進(jìn)行開發(fā)。

注意:要在iOS模擬器或iOS設(shè)備上進(jìn)行構(gòu)建和測試,您需要使用已安裝Xcode的macOS


Creating a new project

在安裝了Flutter擴展的VS Code中,通過選擇View ? Command Palette…或在macOS上單擊Cmd-Shift-P或在Linux或Windows上單擊Ctrl-Shift-P來打開命令面板。 在面板中輸入Flutter:New Project,然后按回車鍵。

輸入項目的名稱ghflutter,然后按回車鍵。 選擇一個文件夾來存儲項目,然后等待Flutter在VS Code中設(shè)置項目。 項目準(zhǔn)備就緒后,將在編輯器中打開文件main.dart

VS Code中,您會在左側(cè)看到一個面板,該面板顯示您的項目結(jié)構(gòu)。 有適用于iOS和Android的文件夾,還有一個包含main.dartlib文件夾,并且具有適用于兩個平臺的代碼。 僅在本教程中,您將在lib文件夾中工作。

用以下內(nèi)容替換main.dart中的代碼:

import 'package:flutter/material.dart';

void main() => runApp(GHFlutterApp());


class GHFlutterApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'GHFlutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('GHFlutter'),
        ),
        body: Center(
          child: Text('GHFlutter'),
        ),
      ),
    );
  }
}

頂部附近的main()函數(shù)對單個行函數(shù)使用=>運算符來運行該應(yīng)用程序。 您有一個名為GHFlutterApp的應(yīng)用程序類。

您在這里看到您的應(yīng)用程序本身是一個StatelessWidget。 Flutter應(yīng)用程序中的大多數(shù)實體都是無狀態(tài)或有狀態(tài)的widgets。 您可以覆蓋widgetsbuild()方法來創(chuàng)建應(yīng)用widgets。 您正在使用MaterialApp widgets,該widgets提供了Material Design之后的應(yīng)用所需的許多組件。

對于本入門教程,通過右鍵單擊,選擇Delete選項,然后確認(rèn)刪除,從項目中刪除test文件夾中的測試文件widget_test.dart

如果您使用的是macOS,請啟動iOS模擬器。 您也可以在macOS,Linux或Windows上使用Android模擬器。 如果iOS模擬器和Android模擬器都在運行,則可以使用VS Code窗口右下方的菜單在它們之間進(jìn)行切換:

要構(gòu)建和運行項目,您需要首先設(shè)置啟動配置。

通過單擊左側(cè)面板上的crossed bug圖標(biāo),切換到Debug View

您會注意到,到目前為止,尚未定義任何配置。 單擊No Configuration以獲取下拉列表并選擇Add Configuration

VS Code將創(chuàng)建一個launch.json文件,其詳細(xì)信息如下:

注意:選擇Add Configuration項后,將自動為您生成此文件。 在本教程中,您無需修改它。

現(xiàn)在,您已經(jīng)完成所有工作,可以通過按F5或選擇Debug ? Start Debugging或單擊綠色的播放圖標(biāo)來構(gòu)建和運行項目。 您會看到Debug Console已打開,并且如果在iOS上運行,則會看到用于構(gòu)建項目的Xcode。 如果在Android上運行,則會看到Gradle被調(diào)用以進(jìn)行構(gòu)建。

這是在iOS模擬器中運行的應(yīng)用程序:

下面,在Android模擬器中運行:

您看到的慢速模式banner表明該應(yīng)用程序正在調(diào)試模式下運行。

您可以通過單擊VS Code窗口頂部工具欄右側(cè)的停止按鈕來停止正在運行的應(yīng)用程序:

通過單擊VS Code左上方的圖標(biāo)或選擇View ? Explorer,可以返回項目視圖。


Hot Reload

Flutter開發(fā)的最佳方面之一是能夠在進(jìn)行更改時熱重新加載您的應(yīng)用程序。 這類似于Android StudioInstant Run/Apply Changes

構(gòu)建并運行該應(yīng)用程序,使其在模擬器或模擬器上運行:

現(xiàn)在,無需停止正在運行的應(yīng)用程序,請將應(yīng)用程序欄字符串更改為其他內(nèi)容:

appBar: AppBar(
  title: Text('GHFlutter App'),
),

現(xiàn)在,單擊工具欄上的熱重載按鈕或直接保存main.dart文件:

一兩秒鐘之內(nèi),您應(yīng)該會看到正在運行的應(yīng)用程序中反映出的更改:

熱重載功能可能并不總是有效,官方文檔official docs可以很好地解釋無法使用的情況,但總體而言,在構(gòu)建UI時可節(jié)省大量時間。


Importing a File

您將希望能夠從創(chuàng)建的其他類中導(dǎo)入代碼,而不是將所有Dart代碼都保存在單個main.dart文件中。 現(xiàn)在,您將看到一個導(dǎo)入字符串的示例,該示例在需要本地化面向用戶的字符串時會有所幫助。

右鍵單擊lib并選擇New File,在lib文件夾中創(chuàng)建一個名為strings.dart的文件:

將以下類添加到新文件中:

class Strings {
  static String appTitle = "GHFlutter";
}

將以下import添加到main.dart的頂部

import 'strings.dart';

更改widget以使用新的字符串類,以便GHFlutterApp類如下所示:

class GHFlutterApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: Strings.appTitle,
      home: Scaffold(
        appBar: AppBar(
          title: Text(Strings.appTitle),
        ),
        body: Center(
          child: Text(Strings.appTitle),
        ),
      ),
    );
  }
}

按下F5鍵即可構(gòu)建并運行該應(yīng)用,您應(yīng)該不會有任何變化,但是現(xiàn)在您正在使用字符串文件中的字符串。


Widgets

Flutter應(yīng)用程序中的幾乎每個元素都是widgetwidget被設(shè)計為不可變的,因為使用不可變的widget有助于使應(yīng)用程序UI保持輕便。

您將使用兩種基本類型的小部件:

  • Stateless - 無狀態(tài):僅依賴于自己的配置信息的widget,例如圖像視圖中的靜態(tài)圖像。
  • Stateful - 有狀態(tài):需要維護(hù)動態(tài)信息并通過與State對象進(jìn)行交互來實現(xiàn)的信息。

無狀態(tài)小部件和有狀態(tài)widget都在Flutter應(yīng)用程序中的每幀上重新繪制,不同之處在于,有狀態(tài)widget將其配置委托給State對象。

要開始制作自己的widget,請在main.dart底部創(chuàng)建一個新類:

class GHFlutter extends StatefulWidget {
  @override
  createState() => GHFlutterState();
}

您已經(jīng)創(chuàng)建了StatefulWidget子類,并且您將覆蓋createState()方法以創(chuàng)建其狀態(tài)對象。 現(xiàn)在,在GHFlutter上方添加GHFlutterState類:

class GHFlutterState extends State<GHFlutter> {
}

GHFlutterState使用GHFlutter的參數(shù)擴展State

制作widget時的主要任務(wù)是覆蓋將widget呈現(xiàn)到屏幕時調(diào)用的build()方法。

GHFlutterState中添加一個build()重寫:

@override
Widget build(BuildContext context) {
?    
}

填寫build()如下:

@override
Widget build(BuildContext context) {
  return Scaffold (
    appBar: AppBar(
      title: Text(Strings.appTitle),
    ),
    body: Text(Strings.appTitle),
  );
}

Scaffold是用于材料設(shè)計widgets的容器。 它充當(dāng)widgets層次結(jié)構(gòu)的根。 您已在Scaffold中添加了一個AppBar和一個body,每個都包含一個Text widget

更新GHFlutterApp,使其使用新的GHFlutter小部件作為其home屬性,而不是構(gòu)建自己的支架:

class GHFlutterApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: Strings.appTitle,
      home: GHFlutter(),
    );
  }
}

構(gòu)建并運行該應(yīng)用程序,您將看到新的widget在起作用:

尚未發(fā)生太大變化,但是現(xiàn)在您可以設(shè)置以構(gòu)建新的widget


Making Network Calls

之前,您已將strings.dart文件導(dǎo)入到項目中。 您可以類似地導(dǎo)入Flutter框架和Dart中包含的其他軟件包。

例如,您現(xiàn)在將使用框架中可用的包進(jìn)行HTTP網(wǎng)絡(luò)調(diào)用,并將生成的響應(yīng)JSON解析為Dart對象。 在main.dart頂部添加兩個新導(dǎo)入:

import 'dart:convert';
import 'package:http/http.dart' as http;

您會注意到http包不可用。 這是因為尚未將其添加到項目中。 導(dǎo)航到pubspec.yaml文件,然后在dependenciescupertino_icons:^ 0.1.2下添加以下內(nèi)容:

  cupertino_icons: ^0.1.2

  # HTTP package
  http: ^0.12.0+2

注意:注意縮進(jìn)。 保持 http 軟件包聲明的縮進(jìn)與 cupertino_icons軟件包的縮進(jìn)相同。

現(xiàn)在,當(dāng)您保存pubspec.yaml文件時,VS Code中的Flutter擴展名將運行flutter pub get命令。 Flutter將獲得聲明的http軟件包,您的軟件包也將在main.dart中可用。

現(xiàn)在,您將在main.dart中看到有關(guān)當(dāng)前未使用的導(dǎo)入的指示器。

Dart應(yīng)用程序是單線程的,但是Dart提供了對在其他線程上運行代碼以及運行異步代碼的支持,這些異步代碼不會使用async / await模式阻止UI線程。

您將進(jìn)行異步網(wǎng)絡(luò)調(diào)用以檢索GitHub團(tuán)隊成員的列表。 在GHFlutterState的頂部添加一個空列表作為屬性,還添加一個屬性以容納文本樣式:

var _members = [];

final _biggerFont = const TextStyle(fontSize: 18.0);

名稱開頭的下劃線使該類的成員成為私有成員。

要進(jìn)行異步HTTP調(diào)用,請向GHFlutterState添加方法_loadData()

_loadData() async {
  String dataURL = "https://api.github.com/orgs/raywenderlich/members";
  http.Response response = await http.get(dataURL);
  setState(() {
    _members = json.decode(response.body);
  });
}

您已經(jīng)在_loadData()上添加了async關(guān)鍵字,以告知Dart它是異步的,并且還在http.get()調(diào)用上阻塞了await關(guān)鍵字。 您使用的dataUrl值設(shè)置為GitHub API端點,該端點檢索GitHub組織的成員。

HTTP調(diào)用完成后,您將向回調(diào)傳遞給setState(),該回調(diào)在UI線程上同步運行。 在這種情況下,您將解碼JSON響應(yīng)并將其分配給_members列表。

initState()重寫添加到GHFlutterState,該狀態(tài)在初始化狀態(tài)時調(diào)用_loadData()

@override
void initState() {
  super.initState();

  _loadData();
}

Using a ListView

現(xiàn)在您已經(jīng)有了Dart成員列表,您需要一種在UI列表中顯示它們的方法。 Dart提供了一個ListView widget,可讓您在列表中顯示數(shù)據(jù)。 ListView的行為類似于Android上的RecyclerView和iOS上的UITableView,在用戶滾動列表以實現(xiàn)平滑滾動性能時回收視圖。

_buildRow()方法添加到GHFlutterState中:

Widget _buildRow(int i) {
  return ListTile(
    title: Text("${_members[i]["login"]}", style: _biggerFont)
  );
}

您將返回一個ListTile widget,該widget顯示從ith成員的JSON解析的login值,并使用您之前創(chuàng)建的文本樣式。

更新GHFlutterState的構(gòu)建方法,使其主體為ListView.builder

body: ListView.builder(
  padding: const EdgeInsets.all(16.0),
  itemCount: _members.length,
  itemBuilder: (BuildContext context, int position) {
    return _buildRow(position);
  }),

你已經(jīng)添加paddingitemCount設(shè)置為成員的數(shù)量,并使用_buildRow()為給定的位置設(shè)置itemBuilder

您可以嘗試熱重載,但可能會收到“Full restart may be required”消息。 如果是這樣,請按F5鍵構(gòu)建并運行該應(yīng)用程序:

進(jìn)行網(wǎng)絡(luò)通話,解析數(shù)據(jù)并在列表中顯示結(jié)果就是這么簡單!


Adding dividers

要將分隔符添加到列表中,您需要將item數(shù)量加倍,然后在列表中的位置為奇數(shù)時返回Divider widget。 如下更新GHFlutterState的構(gòu)建方法:

body: ListView.builder(
  itemCount: _members.length * 2,
  itemBuilder: (BuildContext context, int position) {
    if (position.isOdd) return Divider();

    final index = position ~/ 2;
    
    return _buildRow(index);
  }),

確保不要錯過itemCount上的* 2。 有了分隔線后,您已經(jīng)從構(gòu)建器中刪除了padding。 在itemBuilder中,您要么返回Divider(),要么通過整數(shù)除法并使用_buildRow()來構(gòu)建行項目來計算新索引。

嘗試熱重載,您應(yīng)該在列表上看到分隔線:

要將padding重新添加到每一行中,您想在_buildRow()中使用Padding widget

Widget _buildRow(int i) {
  return Padding(
    padding: const EdgeInsets.all(16.0),
    child: ListTile(
      title: Text("${_members[i]["login"]}", style: _biggerFont)
    )
  );
}

ListTile現(xiàn)在是padding widget的子widget。 熱重新加載以查看行上的padding,而不是分隔線上的padding


Parsing to Custom Types

在上一節(jié)中,JSON解析器將JSON響應(yīng)中的每個成員作為Dart Map類型添加到_members列表中,相當(dāng)于Kotlin中的MapSwift中的Dictionary

但是,您還希望能夠使用自定義類型。

main.dart文件中添加一個新的Member類型:

class Member {
  final String login;

  Member(this.login) {
    if (login == null) {
      throw ArgumentError("login of Member cannot be null. "
          "Received: '$login'");
    }
  }
}

成員具有login屬性和一個構(gòu)造函數(shù),如果登錄值為null,則該構(gòu)造函數(shù)將拋出錯誤。

更新GHFlutterState中的_members聲明,以便它是Member對象的列表:

var _members = <Member>[];

更新_buildRow()以在Member對象上使用login屬性,而不是使用映射上的login鍵:

title: Text("${_members[i].login}", style: _biggerFont)

現(xiàn)在,更新發(fā)送到_loadData()中的setState()的回調(diào),以將解碼后的映射轉(zhuǎn)換為Member對象并將其添加到成員列表中:

setState(() {
  final membersJSON = json.decode(response.body);

  for (var memberJSON in membersJSON) {
    final member = Member(memberJSON["login"]);
    _members.add(member);
  }
});

如果嘗試進(jìn)行熱重裝,您可能會看到一個錯誤,但是停止并按F5鍵來構(gòu)建和運行該應(yīng)用,您應(yīng)該會看到與以前相同的屏幕,除了現(xiàn)在使用新的Member類。


Downloading Images with NetworkImage

來自GitHub的每個成員都有其頭像的URL。 現(xiàn)在,您將該頭像添加到Member類中,并在應(yīng)用程序中顯示頭像。

更新Member類以添加一個avatarUrl屬性,該屬性不能為null

class Member {
  final String login;
  final String avatarUrl;

  Member(this.login, this.avatarUrl) {
    if (login == null) {
      throw ArgumentError("login of Member cannot be null. "
          "Received: '$login'");
    }
    if (avatarUrl == null) {
      throw ArgumentError("avatarUrl of Member cannot be null. "
          "Received: '$avatarUrl'");
    }
  }
}

使用NetworkImageCircleAvatar widget更新_buildRow()以顯示頭像:

Widget _buildRow(int i) {
  return Padding(
    padding: const EdgeInsets.all(16.0),
    child: ListTile(
      title: Text("${_members[i].login}", style: _biggerFont),
      leading: CircleAvatar(
        backgroundColor: Colors.green,
        backgroundImage: NetworkImage(_members[i].avatarUrl)
      ),
    )
  );
}

通過將頭像設(shè)置為ListTileleading屬性,它將在行內(nèi)標(biāo)題之前顯示。 您還使用Colors類在圖片上設(shè)置了背景色。

現(xiàn)在更新_loadData()以在創(chuàng)建新Member時使用映射中的“ avatar_url”值:

final member = Member(memberJSON["login"], memberJSON["avatar_url"]);

使用F5停止,構(gòu)建和運行該應(yīng)用程序。 您會在每一行中看到您的成員頭像:


Cleaning the Code

現(xiàn)在,您的大多數(shù)代碼都位于main.dart文件中。 為了使代碼更簡潔,您可以重構(gòu)已添加到文件中的widget和其他類。

lib文件夾中創(chuàng)建名為member.dartghflutter.dart的文件。 將Member類移至member.dart,并將GHFlutterStateGHFlutter類移至ghflutter.dart

您在member.dart中不需要任何import語句,但是ghflutter.dart中的導(dǎo)入應(yīng)如下所示:

import 'dart:convert';
import 'package:http/http.dart' as http;

import 'package:flutter/material.dart';

import 'member.dart';
import 'strings.dart'; 

您還需要更新main.dart中的導(dǎo)入,以便整個文件包含以下內(nèi)容:

import 'package:flutter/material.dart';

import 'ghflutter.dart';
import 'strings.dart';

void main() => runApp(GHFlutterApp());


class GHFlutterApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: Strings.appTitle,
      home: GHFlutter(),
    );
  }
}  

按下F5來構(gòu)建和運行該應(yīng)用程序,您應(yīng)該看不到任何更改,但是代碼現(xiàn)在更簡潔了。


Adding a Theme

您可以通過將theme屬性添加到您在main.dart中創(chuàng)建的MaterialApp中,輕松地將主題添加到應(yīng)用中:

class GHFlutterApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: Strings.appTitle,
      theme: ThemeData(primaryColor: Colors.green.shade800), 
      home: GHFlutter(),
    );
  }
}  

您將綠色用作主題的“材料設(shè)計”顏色值。

按下F5來構(gòu)建和運行應(yīng)用程序,以查看新的主題:

大多數(shù)應(yīng)用程序屏幕截圖均來自Android模擬器。 您還可以在iOS模擬器中運行最終的主題應(yīng)用程序:

這就是我所說的跨平臺!

有關(guān)FlutterDart的知識還有很多。 最好的起點是:

  • flutter.dev上的Flutter主頁。 您會發(fā)現(xiàn)很多很棒的文檔和其他信息。
  • 在此處here查看可用的widgets
  • 這里here有一個很好的指南供Android開發(fā)人員過渡到使用Flutter
  • 適用于React Native開發(fā)人員的類似指南在這里here

后記

本篇主要講述了Flutter 入門,感興趣的給個贊或者關(guān)注~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內(nèi)容