SF Symbols详细介绍(二) —— 简单使用介绍(一)

版本记录

版本号 时间
V1.0 2021.05.21 星期五

前言

SF Symbols 在 WWDC 2019 期间推出。自此Apple 为我们提供了免费 Symbols,供我们在应用中使用,而且使用它们非常简单。 不久前,WWDC 2020 又引入了 SF Symbols 2.0,这让我们在 app 中使用精美的图标更加容易。感兴趣的可以看下面几篇文章。
1. SF Symbols详细介绍(一) —— 简介(一)

开始

首先看下主要内容:

学习使用现有和自定义的SF符号来以引人入胜的方式显示数据。内容来自翻译

接着看下写作环境:

Swift 5, iOS 14, Xcode 12

下面就是正文啦。

在本教程中,您将学习有关SF Symbols的所有知识,以及如何创建自己的自定义符号以帮助您的应用脱颖而出!

SF Symbols是由Apple策划的超过2,400个符号或图标的集合。它们旨在与Apple设备(称为San Francisco)上的默认系统字体配合使用。由于它们具有多种sizes and weights,它们提供了一种向项目添加图标的简便方法。有许多现成的选项,您很可能会找到适合您应用风格的完美选择。而且,如果您找不到所需的东西,可以创建它。

在这里,您将向应用程序中添加新的金光闪闪图标,以显示London Underground线(通常称为地铁)的状态。在此过程中,您将学习如何:

  • SF Symbols集成到您的应用程序中。
  • 将不同的SF符号与不同的状态相关联。
  • 创建自己的自定义符号以在您的应用中使用。

首先在Xcode中打开入门项目。

该应用程序显示Tube线的当前状态。您可以通过将SF符号与每个状态相关联并将其显示在应用中来添加到项目中。这样,用户可以一目了然地获得所需的信息。

构建并运行该应用程序。

哦!错误!这是因为您需要设置应用程序以获取管线的数据。在逐步了解该应用程序的工作原理之后,现在您将执行此操作。

注意:如果您对了解应用程序的内部运作方式不感兴趣,则可以跳至Setting up TransportAPI

1. Getting Acquainted with the App

打开AppMain.swift。主视图显示一个名为TubeStatusView的视图,该视图充当应用程序的根视图。

接下来,打开TubeStatusView.swiftTubeStatusView观察到TubeStatusViewModel类型的模型对象。视图的body显示ZStack,该ZStack设置视图的背景色,然后在顶部显示Loadable

可加载项根据加载状态显示不同的内容:

  • 等待数据时旋转的活动指示器。
  • 如果加载数据失败,将发生错误。
  • 数据成功加载后,视图构建器的内容。

数据加载完成后,TubeStatusView将为每行显示LineStatusRow。这些包含在ScrollView中。它还显示Text,显示上次更新数据的时间。

请注意,视图还如何包含onAppear(perform :)。当视图第一次出现在屏幕上时,它将调用视图的loadData()。此方法通过调用perform(action :)来要求模型执行fetchCurrentStatus

打开LineStatusRow.swift并快速浏览一下。这是一个简单的视图,显示特定管道线的状态。您可以查看SwiftUI预览以查看这些行的外观。

2. Importing Models and Data

接下来,打开TubeStatusViewModel.swift。该类的重要部分在ActionsAction Handlers下标记。

您已经了解了TubeStatusView在屏幕上显示时如何调用perform(action :)。通过将fetchCurrentStatus枚举作为操作传递,此方法将调用fetchCurrentStatus()

fetchCurrentStatus()对符合TubeLinesStatusFetcher协议类型的实例变量调用fetchStatus()。这可以处理从API获取数据的操作。一旦获取,tubeStatusState将被更新。由于这是已发布的对象,SwiftUI会自动处理UI的更新。

3. Adding TransportAPI Functionality

API组中打开TransportAPIService.swift。 此类处理从fetchStatus()中的网络请求中获取JSON数据,并将JSON解码为AllLinesStatus结构。

在该类中需要注意的重要部分是第8283行上的appIdappKey。这些值是从应用程序的Info.plist(特别是分别从TRANSPORT_API_SERVICE_APP_IDTRANSPORT_API_SERVICE_APP_KEY中加载的。

打开Info.plist。 请注意,这些值并未设置为任何有效的ID,而是设置为$(TRANSPORT_API_SERVICE_APP_ID)$(TRANSPORT_API_SERVICE_APP_KEY)$(...)语法称为变量替换。 它告诉Xcode在构建应用程序时,用配置文件中的键值替换Info.plist中的值。 您稍后将进行设置。

通过单击Project navigator中的TubeStatus项目,打开Project Info面板。 然后,在Project标题下单击TubeStatus

Debug配置将加载Debug配置文件,该配置文件具有与Release相似的设置。


Setting up TransportAPI

该应用程序使用免费的第三方API(称为TransportAPI)来获取有关各种Tube Line的最新信息。 在开始之前,您需要注册并创建一个新应用。

转到the TransportAPI Developer Portal,然后单击标题中的Sign up

填写表格,选中reCAPTCHA复选框,然后单击Sign up。 确认屏幕将要求您检查您的电子邮件。

您会收到两封电子邮件。 第一个包含有关如何激活帐户的详细信息。 第二个确认您已经成功创建了一个新的Application Key

按照第一封电子邮件中的说明激活您的帐户,然后在开发人员门户Developer Portal中登录到您的新帐户。 登陆页面显示了刚刚创建的凭据 —— App ID and App Key。 保持此标签为打开状态,因为稍后将使用这些值。

1. Connecting the API

现在,是时候将Transport API连接到您的应用了。

首先,打开Debug.xcconfig。 在这里,您会找到带有伪值的TRANSPORT_API_SERVICE_APP_IDTRANSPORT_API_SERVICE_APP_KEY。 将每个设置为Transport API开发人员门户提供的值。

构建并运行您的应用程序 —— 最后!

注意:Xcode配置(.xcconfig)文件非常适合为您的应用提供特定于构建的配置。例如,您可以在模拟器上运行时使用staging server URL ,而在生产环境中可以使用其他URL

但是,即使您使用.xcconfig,也不应将API密钥存储在这样的应用程序中。在生产应用程序中,您应该通过自己的服务器代理来自应用程序的请求,并让该服务器代表您向Transport API发出请求。您可以使用 AWS Lambda之类的服务轻松地做到这一点。

然后,如果您需要更改API密钥,或者如果Transport API引入了重大更改,则只需更新服务器,而不需要用户下载应用程序的新版本!


Understanding SF Symbols

现在基本应用已启动并运行,您将在本教程的其余部分中学习如何以SF Symbols的形式添加一些pizazz

SF符号当前提供三个版本:

  • Version 1.1 is available on iOS/iPadOS/tvOS 13 and watchOS 6
  • Version 2.0 is available on iOS/iPadOS/tvOS 14 and watchOS 7.0
  • Version 2.1 is available on iOS/iPadOS/tvOS 14.2 and watchOS 7.2

macOS Big Sur也提供所有版本。

除了添加了将近900个符号外,SF Symbols的版本2还引入了160多种多色符号,局部变体以及对符号水平对齐方式的改进。

注意:某些符号在版本之间已更改其名称。尽管SF Symbols支持旧名称以实现向后兼容性,但您应确保在应用程序中使用的所有符号都可以在您打算支持的所有版本上使用。


Viewing Available Symbols

苹果已经为macOS发布了SF Symbols app for macOS,其中展示了所有可用的符号。 下载该应用程序并打开它。

左侧面板用作过滤器,可根据类别限制显示哪些符号。

顶部窗格允许您执行以下操作:

  • 更改显示符号的字体和粗细。
  • 在网格或列表之间切换布局。
  • 切换多色预览。
  • 按名称过滤符号。

单击顶部栏上的i按钮时,将打开一个右侧窗格。 此窗格提供了所有选定符号的详细视图,包括可用的平台及其使用限制。

最后,主窗格基于所选选项显示所有相关符号。


Using SF Symbols

终于该启动您的应用了。 在Xcode中,在LineData组中打开TFLLineStatus.swift。 该文件定义一个enum,其中包含API支持的所有行状态值。 有很多!

在文件末尾的最后一个大括号之前,添加以下代码:

// 1
func image() -> Image {
  switch self {
  default:
    // 2
    return Image(systemName: "exclamationmark.octagon")
  }
}

在此代码中,您:

  • 1) 将新方法image()添加到TFLLineStatus
  • 2) 在Image上使用新的init(systemName :)创建一个带有exclamationmark.octagon SF Symbol的图像。

SF Symbols应用程序中搜索exclamationmark.octagon

接下来,在显示行的状态时将使用此图像。 打开LineStatusRow.swift

VStack之前,将以下内容作为HStack的第一个child添加到正文中:

// 1
status.image()
  // 2
  .font(.title)
  .padding(.trailing)
  .foregroundColor(lineColor.contrastingTextColor)

这里:

  • 1) 调用您在TFLLineStatus上定义的status.image(),以将状态图像插入HStack的前端。
  • 2) 使用视图修改器在图像上设置字体样式,填充和前景色属性。 设置前景色,使其与行的背景色形成鲜明对比。

注意如何在Image上调用font(_ :)。 由于SF Symbols设计为可与San Francisco字体系统一起使用,因此它们会根据您提供的字体自动选择正确的变体。 整洁的!

构建并运行该应用程序。

Voilà,您刚刚将第一个SF Symbol添加到了应用中。 恭喜你!

但是,对于每个状态代码使用相同的符号对用户来说并不太有用。 要解决此问题,请返回到TFLLineStatus.swift。 将以下内容置于default之前的switchbody中:

case .closed:
  return Image(systemName: "exclamationmark.octagon")
case .suspended:
  return Image(systemName: "nosign")
case .severeDelays:
  return Image(systemName: "exclamationmark.arrow.circlepath")
case .reducedService:
  return Image(systemName: "tortoise")
case .busService:
  return Image(systemName: "bus")
case .minorDelays:
  return Image(systemName: "clock.arrow.circlepath")
case .goodService:
  return Image(systemName: "checkmark.square")
case .changeOfFrequency:
  return Image(systemName: "clock.arrow.2.circlepath")
case .notRunning:
  return Image(systemName: "exclamationmark.octagon")
case .issuesReported:
  return Image(systemName: "exclamationmark.circle")
case .noIssues:
  return Image(systemName: "checkmark.square")
case .plannedClosure:
  return Image(systemName: "hammer")
case .serviceClosed:
  return Image(systemName: "exclamationmark.octagon")
case .unknown:
  return Image(systemName: "questionmark.circle")

在此代码中,您将挑选出几种常见的状态代码,并为每个代码提供自定义的SF符号。 未指定的任何代码将继续使用switch’s default case下的exclamationmark.octagon符号。

再次构建并运行该应用程序。 根据您运行应用程序时Tube系统的状态,您的体验可能与下图有所不同。 但希望您会看到许多类型的状态显示不同的图像。

整洁!希望您开始看到强大的SF符号!


Testing with Mock Data

在上一节中,您为不同的线路状态选择了不同的SF符号。但是,由于您的应用仅呈现行的当前状态,因此您尚未能够看到它们的外观。现在,您将探索使用模拟数据来测试所有状态。

1. Naïve Mock Data Approaches

您可以等到现实中的每种状态出现后,再快速打开该应用程序。但是您可能等待了很长时间。

另一个选择是向LineStatusRow添加许多Swift UI预览,并适当地设置属性。可以,但是笨拙。

每个预览都会在手机屏幕背景上单独显示。交互性不可用,而且最糟糕的是,由于LineStatusRow是纯粹的演示视图,因此您只需要检查预览中提供的值是否正确呈现即可。

另一种方法是使用unit tests and mock data。这是一个很好的方法,但是仍然缺少交互性元素。

2. Using Mock Data with Environment Variables

另一种可能更有用的方法是根据环境变量为您的应用配置mock data。这样,您可以选择使用所需的任何数据来构建应用程序,然后将其在模拟器或设备上进行播放,就好像它是真实的一样。

Xcode中,选择Product ▸ Scheme ▸ Edit Schemes…,然后选择Duplicate Scheme

new scheme命名为Debug Data,然后单击Close。 然后,选择Product ▸ Schemes ▸ Manage Schemes…,选择Debug Data scheme,然后选择Edit…

在左侧菜单中选择Run,然后选择Arguments tab。 单击Environment Variables下的+图标,然后创建一个名为USE_DEBUG_DATA的新环境变量,其值为true。 单击Close

您的应用程序现在具有两个schemes,除了DebugData将您的新环境变量传递到构建环境外,它们是相同的。

接下来,打开DebugLineData.swift并在导入声明之后立即添加以下代码:

// 1
let bakerlooLineDebug = LineData(
  name: "BakerlooDebug", 
  color: Color(red: 137 / 255, green: 78 / 255, blue: 36 / 255))
let centralLineDebug = LineData(
  name: "CentralDebug", 
  color: Color(red: 220 / 255, green: 36 / 255, blue: 31 / 255))
let circleLineDebug = LineData(
  name: "CircleDebug", 
  color: Color(red: 255 / 255, green: 206 / 255, blue: 0 / 255))
let districtLineDebug = LineData(
  name: "DistrictDebug", 
  color: Color(red: 0 / 255, green: 114 / 255, blue: 41 / 255))
let hammersmithAndCityLineDebug = LineData(
  name: "Hammersmith & CityDebug",
  color: Color(red: 215 / 255, green: 153 / 255, blue: 175 / 255))
let jubileeLineDebug = LineData(
  name: "JubileeDebug", 
  color: Color(red: 106 / 255, green: 114 / 255, blue: 120 / 255))
let metropolitanLineDebug = LineData(
  name: "MetropolitanDebug", 
  color: Color(red: 117 / 255, green: 16 / 255, blue: 86 / 255))
let northernLineDebug = LineData(
  name: "NorthernDebug",
  color: Color(red: 0 / 255, green: 0 / 255, blue: 0 / 255))
let piccadillyLineDebug = LineData(
  name: "PiccadillyDebug",
  color: Color(red: 0 / 255, green: 25 / 255, blue: 168 / 255))
let victoriaLineDebug = LineData(
  name: "VictoriaDebug",
  color: Color(red: 0 / 255, green: 160 / 255, blue: 226 / 255))

然后,在底部的debugData常量声明内的lineStatus的方括号之间添加以下内容:

// 2
LineStatus(line: bakerlooLine, status: .specialService),
LineStatus(line: centralLine, status: .closed),
LineStatus(line: circleLine, status: .suspended),
LineStatus(line: districtLine, status: .partSuspended),
LineStatus(line: hammersmithAndCityLine, status: .plannedClosure),
LineStatus(line: jubileeLine, status: .partClosure),
LineStatus(line: metropolitanLine, status: .severeDelays),
LineStatus(line: northernLine, status: .reducedService),
LineStatus(line: piccadillyLine, status: .busService),
LineStatus(line: victoriaLine, status: .minorDelays),
LineStatus(line: waterlooAndCityLine, status: .goodService),
LineStatus(line: dlr, status: .partClosed),
// 3
LineStatus(line: bakerlooLineDebug, status: .exitOnly),
LineStatus(line: centralLineDebug, status: .noStepFreeAccess),
LineStatus(line: circleLineDebug, status: .changeOfFrequency),
LineStatus(line: districtLineDebug, status: .diverted),
LineStatus(line: hammersmithAndCityLineDebug, status: .notRunning),
LineStatus(line: jubileeLineDebug, status: .issuesReported),
LineStatus(line: metropolitanLineDebug, status: .noIssues),
LineStatus(line: northernLineDebug, status: .information),
LineStatus(line: piccadillyLineDebug, status: .serviceClosed),
LineStatus(line: victoriaLineDebug, status: .unknown)

这段代码:

  • 1) 创建多条“假”管线。您的应用程序有21个状态代码,但只有12行。因此,您另外创建了9行,以确保有足够的行来显示每个代码。
  • 2) 将LineStatus项目添加到DebugDatalineStatus。第一组为每个“实际”管道添加了不同的状态代码。
  • 3) 第二组将剩余的状态代码添加到您创建的假管线中。

3. Switching Between Mock Data and Actual Data

现在,查看DebugDataService.swift。这里只有几行代码,但还有很多事情要做!这是此文件中的代码的作用:

  • 1) 首先,文件导入Combine使其可以访问Future类。
  • 2) 接下来,它将DebugDataService定义为符合TubeLinesStatusFetcher
  • 3) 然后,它实现fetchStatus —— TubeLinesStatusFetcher唯一需要的方法。
  • 4) 最后,它返回包装在Future中的debugData。该debugData是您在上一节中添加的数据。

要使用调试行状态获取程序,请创建一个名为TubeLinesStatusFetcherFactory.swiftSwift文件,并添加以下代码:

// 1
enum TubeLinesStatusFetcherFactory {
  // 2
  static func new() -> TubeLinesStatusFetcher {
    // 3
    #if DEBUG
    if ProcessInfo.processInfo.environment["USE_DEBUG_DATA"] == "true" {
      return DebugDataService()
    }
    #endif
    // 4
    return TransportAPIService()
  }
}

这是正在发生的事情:

  • 1) 由于您只想在该实体上使用静态方法,因此将其实现为无大小写的枚举(caseless enum)。 您可以在这里使用结构体,但是可以不必要地实例化结构体,因此enum是一个更好的选择。
  • 2) 定义一个静态方法new(),该方法返回符合TubeLineStatusFetcher的对象。
  • 3) 如果以调试模式运行并且USE_DEBUG_DATA设置为true,则返回以前创建的DebugDataService的实例。
  • 4) 否则,返回TransportAPIService的实例,该实例从Transport API获取实际数据。

最后,打开AppMain.swift并找到以下行:

model: TubeStatusViewModel(tubeLinesStatusFetcher: TransportAPIService())

将其替换为以下内容:

model: TubeStatusViewModel(
  tubeLinesStatusFetcher: TubeLinesStatusFetcherFactory.new())

在这里,您要添加另一层间接性,并使用TubeLinesStatusFetcherFactory决定为其提供的任何访存器来初始化TubeStatusViewModel,而不是直接使用TransportAPIService

4. Using the DebugData Scheme

现在,该测试一下了! 确保选择Debug Data scheme

现在,构建并运行该应用程序。

这是面向协议的编程 protocol-oriented programming和依赖项注入的强大功能和灵活性的一个很好的例子。

通过将数据获取服务作为依赖项传递到TubeStatusViewModel中,可以很轻松地用另一种实现替换如何获取数据。

通过仅向TubeStatusViewModel提供数据获取服务用于返回数据(而不是实现)的协议,视图模型不会处理如何获取数据。它可以是硬编码的,也可以通过JSON API下载。


Understanding Restrictions on Using SF Symbols

在发疯并在各处添加SF符号之前,请注意,在何处以及如何使用它们均存在限制。

直接引自苹果公司的Human Interface Guidelines

“You may not use SF Symbols — or glyphs that are substantially or confusingly similar — in your app icons, logos, or any other trademark-related use. Apple reserves the right to review and, in its sole discretion, require modification or discontinuance of use of any Symbol used in violation of the foregoing restrictions, and you agree to promptly comply with any such request.”

此外,SF符号被认为是系统提供的图像,因此受Xcode and Apple SDK license agreements涵盖。

此外,除Apple专有技术外,不允许将124SF符号导出,修改或用于任何其他目的。

Apple将发布这些更受限制的图标的full listSF Symbols应用程序的右侧窗格还详细说明了选择符号时的所有其他限制。


Creating Custom SF Symbols

即使AppleSF Symbol库中提供了数千种不同的符号,也无法覆盖您在应用程序中可能需要的所有可能的图像。苹果所做的反而是使您在需要时可以非常轻松地构建自己的自定义符号。

SF Symbols是使用非常特定的格式在SVG文件中构建为矢量图形的。在顶层,文件必须包含三层:Symbols, GuidesNotes。这些层中的每一个都包含子层。例如,Symbols层包含27个子层 —— 每个可用变体都一层。

此外,Apple允许您从SF Symbols应用程序中导出现有符号,从而可以轻松创建自己的符号。这样,所有格式都已经存在,您只需要更改要自定义的内容即可。

构建自定义符号时,最好找到一个与您要绘制的内容尽可能接近的内置符号,然后使其适应您的需求。

现在,您将了解如何在应用程序中添加自定义符号。


Making an “Information” Symbol

对于此部分,您需要一个可以编辑SVG图像的矢量艺术应用程序。

提供许多不同的选项,包括Adobe IllustratorSketch, FigmaAffinity Designer等付费产品。其中大多数提供免费试用。还提供开源产品,例如InkscapeOpenOffice Draw

本教程使用Affinity Designer,但其他矢量艺术应用程序的过程应相似。

1. Importing the Exclamation Mark Symbol

Mac上打开SF Symbols应用程序,然后搜索exclamationmark.circle符号。选择它,然后选择File ▸ Export Custom Symbol Template…。将符号模板保存在计算机上,然后在矢量图形应用程序中将其打开。

如您所见,SVG文件针对9种字体粗细和3种大小分别包含27个单独的图像。

更新所有27张图像将花费很长时间,但是幸运的是,您不需要更改任何不使用的图像。 您在这里所需的唯一变体是Regular-M,因为这是该应用程序使用的所有东西。 Apple建议您创建常规S / M / L和半粗体S / M / L,因为许多常见的UIKit控件都使用这些变体。

2. Customizing the Exclamation Mark Symbol

在画布中心附近找到Regular-M变体。 每个符号在SVG中作为一个组构建。 删除圆圈中心的感叹号。 您可能需要先取消分层图层,具体取决于您使用的矢量艺术应用程序。

接下来,在该图层中添加一个文本块,然后输入一个小写的i。 在SF Pro中将其大小调整为64pt,重量Heavy。 然后将其放在圆的中心。

自定义SF符号中的每个变体只能包含形状/曲线。 它们不得包含文本,位图或任何其他类型的对象。 将您的i文字图层转换为曲线。 在Affinity Designer中,通过选择Layer ▸ Convert to Curves来执行此操作。

确保新层是Regular-M组的子层。 然后,将新符号保存或导出为称为information.svgSVG

切换到SF Symbols应用程序,然后选择File▸Validate Custom Symbols…,然后选择刚刚保存的文件。 如果您正确完成了所有操作,那么您的新符号将通过验证 —— 耶!


Using Custom Symbols

在应用程序中使用自定义符号非常简单。 切换到Xcode,然后在左侧的Project导航器中选择主要资产目录Assets.xcassets。 切换到Finder并将新的SF Symbol拖动到资产目录中。

确认Regular-M变体在圆圈中是字母i,而不是圆圈中的感叹号。

接下来,切换到Finder并打开在教程开始时下载的资料中的Custom Symbols目录。 将所有六个自定义符号也拖到资产目录中。 或者,使用您的矢量图形应用程序和新发现的知识来创建您自己的自定义符号集。

加载自定义符号使用的API与用于加载提供的SF符号之一的API不同。 不必在Image上调用init(systemName :),而可以使用默认的初始化程序init()

切换回Xcode并打开TFLLineStatus.swift。 在image()的底部,将以下代码替换为default

case .specialService:
  return Image("special.service")
case .partSuspended:
  return Image("part.suspended")
case .partClosure:
  return Image("part.closure")
case .partClosed:
  return Image("part.closure")
case .exitOnly:
  return Image("exit.only")
case .noStepFreeAccess:
  return Image("no.step.free.access")
case .diverted:
  return Image("diverted")
case .information:
  return Image("information")

确保仍然选择Debug Data scheme。 然后,构建并运行您的应用程序。

您已经成功将自定义符号添加到了Tube Status应用中!


Supporting Older Operating Systems

最后,快速提示!

如果您需要支持较早的操作系统版本,但仍想在应用中使用SF Symbols,请使用以下变通办法。 只需从SF Symbols macOS应用程序导出SVG,然后在矢量图形应用程序(如Sketch,Affinity DesignerFigma)中将其打开。

将要用作PNG的图层导出,并将其作为资产添加到应用程序的资产目录中。 然后,只需使用默认的初始化程序,而不要在Image中使用init(systemName :)

您将无法使用SF Symbols提供的高级功能,但仍可以使用图像。

如您所见,使用内置的SF Symbols和提供自己的自定义符号对Swift来说都非常容易。

如果您想观看有关如何在Affinity Designer中构建自己的自定义符号的视频,则Caroline Begbie汇集了出色而快速的演示demonstration

您还应该查看有关在2019年和2020年WWDC事件中介绍SF Symbols的视频,以及有关SF Symbols的AppleHuman Interface Guidelines的文档。

您可以从Apple学习有关creating your custom symbols,的所有详细信息,最后,别忘了阅读official page for SF Symbols的官方页面。

后记

本篇主要讲述了SF Symbols简单使用介绍,感兴趣的给个赞或者关注~~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容