Flutter:手把手教你使用滚动型列表组件GirdView

前言

主要讲解Flutter常用的滚动型组件GridView组件,希望你们会喜欢。

滚动型组件的用法十分相似,可参考学习ListView组件,因为两者都继承自BoxScrollView

>阅读本文前可阅读文章:


目录


1. 属性介绍

GridView({
  Key key,
  Axis scrollDirection = Axis.vertical, // 列表的滚动方向,可选值:Axis的horizontal、vertical
  bool reverse = false,
  ScrollController controller, // 控制器,与列表滚动相关,比如监听列表的滚动事件
  ScrollPhysics physics, // 列表滚动至边缘后继续拖动的物理效果,Android与iOS效果不同:Android = 波纹状(ClampingScrollPhysics),而iOS = 回弹的弹性效果(BouncingScrollPhysics)。若想不同的平台上呈现各自的效果可使用AlwaysScrollableScrollPhysics,它会根据不同平台自动选用各自的物理效果。若想禁用在边缘的拖动效果,可使用NeverScrollableScrollPhysics
  bool shrinkWrap = false, // 决定列表的长度是否仅包裹其内容的长度。当ListView嵌在一个无限长的容器组件中时,shrinkWrap必须为true,否则Flutter会给出警告;
  EdgeInsetsGeometry padding, // 列表内边距
  double cacheExtent,// 预渲染区域长度,ListView会在其可视区域的两边留一个cacheExtent长度的区域作为预渲染区域(对于ListView.build或ListView.separated构造函数创建的列表,不在可视区域和预渲染区域内的子元素不会被创建或会被销毁);
  List<Widget> children = const <Widget>[], // 容纳子元素的组件数组
  @required this.gridDelegate, // 控制排列子元素的一个委托
})

下面主要讲解属性 gridDelegate:类型 = SliverGridDelegate,是一个抽象类 & 有2个实现类:

  • 类型1:SliverGridDelegateWithFixedCrossAxisCount = 用于固定列数场景
  • 类型2:SliverGridDelegateWithMaxCrossAxisExtent = 用于子元素有最大宽度限制场景

下面将详细介绍

// 类型1:SliverGridDelegateWithFixedCrossAxisCount
 // 应用场景:布局中每一行的列数 = 固定
 // 常用属性(构造函数)
  SliverGridDelegateWithFixedCrossAxisCount({
    @required this.crossAxisCount, // 列数,即一行有几个子元素;
    this.mainAxisSpacing = 0.0, // 主轴方向上的空隙间距;
    this.crossAxisSpacing = 0.0, // 次轴方向上的空隙间距;
    this.childAspectRatio = 1.0, // 子元素的宽高比例。
  })

// 类型2:SliverGridDelegateWithMaxCrossAxisExtent
  // 应用场景:子元素有最大宽度限制
  // 常用属性(构造函数)
  SliverGridDelegateWithMaxCrossAxisExtent({
    this.mainAxisSpacing = 0.0, // 主轴方向上的空隙间距;
    this.crossAxisSpacing = 0.0, // 次轴方向上的空隙间距;
    this.childAspectRatio = 1.0, // 子元素的宽高比例
    @required this.maxCrossAxisExtent, // 子元素的最大宽度可能是多少,然后计算得到合适的列宽
  // 示例:假如手机屏宽375,crossAxisSpacing值为0,
  // maxCrossAxisExtent值 = 125时,网格列数 = 3。因为125 * 3 = 375,刚好,每一列的宽度就是375/3。
  // maxCrossAxisExtent值 = 126时,网格列数 = 3。因为126 * 3 > 375,显示不下,每一列的宽度将是375/3。
  // maxCrossAxisExtent值为124时,网格列数 = 4。因为124 * 3 < 375,仍有多余,每一列的宽度将是375/4。
  })

2. 基础使用(含示例讲解)

2.1 示例1

使用:SliverGridDelegateWithFixedCrossAxisCount = 用于固定列数场景

  • 示例代码
import 'package:flutter/material.dart'; // Material UI组件库

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

// 无状态控件显示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的组件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //标题
      theme: ThemeData(primarySwatch: Colors.blue), //主题色
      home: MyWidget(), // 返回一个Widget对象,用来定义当前应用打开的时候,所显示的界面
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new _MyWidgetState();
  }
}

class _MyWidgetState extends State<MyWidget> {

  ScrollController _controller = new ScrollController(); // 定义控制器

  @override
  void initState() {
    super.initState();
    // 设置监听方法
    _controller.addListener(() {
      print('_controller Listener');
      print(_controller.offset); // 打印滚动位置
    });
  }

  @override
  Widget build(BuildContext context) {
    return GridView(
      scrollDirection: Axis.vertical, // 排列方向
      controller: _controller, // 设置控制器
      padding: EdgeInsets.all(10), // 内边距
      physics: new AlwaysScrollableScrollPhysics(), // 设置到边缘后的效果
      children: getWidgetList(), // 表格数据(仅作demo展示,代码在下方)

      // 设置控制排列子元素的一个委托:固定列数
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 3, // 每列3个
        childAspectRatio: 0.5,//宽高比为1:2
        mainAxisSpacing: 10, // 主轴、次轴方向间隔
        crossAxisSpacing: 10,
      ),
    );
  }

  // GridView数据(仅作demo展示)
  List<String> litems = [
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "10",
    "11",
    "12",
    "13",
    "14",
    "15"
  ];

  List<Widget> getWidgetList() {
    return litems.map((item) => getItemContainer(item)).toList();
  }

  Widget getItemContainer(String item) {
    return Container(
      alignment: Alignment.center,
      child: Text(
        item,
        style: TextStyle(color: Colors.white, fontSize: 20),
      ),
      color: Colors.blue,
    );
  }
}
  • 示意图

2.2 示例2

使用:SliverGridDelegateWithMaxCrossAxisExtent = 用于子元素有最大宽度限制场景

  • 示例代码
import 'package:flutter/material.dart'; // Material UI组件库

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

// 无状态控件显示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的组件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //标题
      theme: ThemeData(primarySwatch: Colors.blue), //主题色
      home: MyWidget(), // 返回一个Widget对象,用来定义当前应用打开的时候,所显示的界面
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new _MyWidgetState();
  }
}

class _MyWidgetState extends State<MyWidget> {

  ScrollController _controller = new ScrollController(); // 定义控制器

  @override
  void initState() {
    super.initState();
    // 设置监听方法
    _controller.addListener(() {
      print('_controller Listener');
      print(_controller.offset); // 打印滚动位置
    });
  }

  @override
  Widget build(BuildContext context) {
    return GridView(
      scrollDirection: Axis.vertical, // 排列方向
      controller: _controller, // 设置控制器
      padding: EdgeInsets.all(10), // 内边距
      physics: new AlwaysScrollableScrollPhysics(), // 设置到边缘后的效果
      children: getWidgetList(), // 表格数据(仅作demo展示,代码在下方)

      // 设置控制排列子元素的一个委托:限制子元素的最大宽度
      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
        maxCrossAxisExtent: 200, //子控件最大宽度为200
        childAspectRatio: 0.5,//宽高比为1:2
        mainAxisSpacing: 10, // 主轴、次轴方向间隔
        crossAxisSpacing: 10,
      ),
    );
  }

  // GridView数据(仅作demo展示)
  List<String> litems = [
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "10",
    "11",
    "12",
    "13",
    "14",
    "15"
  ];

  List<Widget> getWidgetList() {
    return litems.map((item) => getItemContainer(item)).toList();
  }

  Widget getItemContainer(String item) {
    return Container(
      alignment: Alignment.center,
      child: Text(
        item,
        style: TextStyle(color: Colors.white, fontSize: 20),
      ),
      color: Colors.blue,
    );
  }
}
  • 示意图

3. 进阶使用

GridView组件除了上面说的基础使用方式(默认构造函数),还有一些进阶使用:

  • GridView.builder
  • GridView.count
  • GridView.extent
  • GridView.custom

下面,我将详细介绍其使用。

类型1:GridView.builder

a. 特点

根据子元素是否出现在屏幕内而动态创建销毁,减少内存消耗,更高效渲染

b. 应用场景

长列表、数据量不确定(如网络请求)

c. 属性(构造函数)

 GridView.builder({
  Key key,
  Axis scrollDirection = Axis.vertical, // 列表的滚动方向,可选值:Axis的horizontal、vertical
  ScrollController controller, // 控制器,与列表滚动相关,比如监听列表的滚动事件
  ScrollPhysics physics, // 列表滚动至边缘后继续拖动的物理效果,Android与iOS效果不同:Android = 波纹状(ClampingScrollPhysics),而iOS = 回弹的弹性效果(BouncingScrollPhysics)。若想不同的平台上呈现各自的效果可使用AlwaysScrollableScrollPhysics,它会根据不同平台自动选用各自的物理效果。若想禁用在边缘的拖动效果,可使用NeverScrollableScrollPhysics
  bool shrinkWrap = false, // 决定列表的长度是否仅包裹其内容的长度。当ListView嵌在一个无限长的容器组件中时,shrinkWrap必须为true,否则Flutter会给出警告;
  EdgeInsetsGeometry padding, // 列表内边距
  double cacheExtent,// 预渲染区域长度,ListView会在其可视区域的两边留一个cacheExtent长度的区域作为预渲染区域(对于ListView.build或ListView.separated构造函数创建的列表,不在可视区域和预渲染区域内的子元素不会被创建或会被销毁);
  List<Widget> children = const <Widget>[], // 容纳子元素的组件数组
  @required this.gridDelegate, // 控制排列子元素的一个委托

  // 上面属性同默认构造函数,主要关注下面两个特别的属性
  @required IndexedWidgetBuilder itemBuilder,// 列表项构造器,返回一个Widget
  int itemCount, // 列表的数量,一般都是集合的长度
  })

d. 示例代码

import 'package:flutter/material.dart'; // Material UI组件库

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

// 无状态控件显示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的组件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //标题
      theme: ThemeData(primarySwatch: Colors.blue), //主题色
      home: MyWidget(), // 返回一个Widget对象,用来定义当前应用打开的时候,所显示的界面
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new _MyWidgetState();
  }
}

class _MyWidgetState extends State<MyWidget> {

  ScrollController _controller = new ScrollController(); // 定义控制器

  // GridView数据(仅作demo展示)
  List<String> litems = [
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "10",
    "11",
    "12",
    "13",
    "14",
    "15"
  ];

  @override
  void initState() {
    super.initState();
    // 设置监听方法
    _controller.addListener(() {
      print('_controller Listener');
      print(_controller.offset); // 打印滚动位置
    });
  }

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      scrollDirection: Axis.vertical, // 排列方向
      controller: _controller, // 设置控制器
      padding: EdgeInsets.all(10), // 内边距
      physics: new AlwaysScrollableScrollPhysics(), // 设置到边缘后的效果
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( // 设置控制排列子元素的一个委托:固定列数
        crossAxisCount: 3, // 每列3个
        childAspectRatio: 0.5,//宽高比为1:2
        mainAxisSpacing: 10, // 主轴、次轴方向间隔
        crossAxisSpacing: 10,
      ),

        // 设置元素数量 & 具体元素(仅作demo展示,代码在下方)
        itemCount: litems.length,
        itemBuilder: (BuildContext ctxt, int index) {
          // 当数据加载完毕时 追加数据
          if (index == litems.length - 1 && litems.length < 200) {
            _addIndex();
          }
          return Container(
            alignment: Alignment.center,
            child: Text(
              litems[index],
              style: TextStyle(color: Colors.white, fontSize: 20),
            ),
            color: Colors.blue,
          );
        }
    );
  }

  void _addIndex() {
    // 此处需延时加载  否则会抱The widget on which setState() or markNeedsBuild() was called was:错误
    Future.delayed(Duration(milliseconds: 200)).then((e) {
      setState(() {
        litems.add("add");
      });
    });
  }
}

e. 示意图


类型2:GridView.count

a. 特点

封装了SliverGridDelegateWithFixedCrossAxisCount

b. 应用场景

布局中每一行的列数 = 固定

c. 属性(构造函数)

GridView.count({
   Key key,
   Axis scrollDirection = Axis.vertical, // 列表的滚动方向,可选值:Axis的horizontal、vertical
   @required this.crossAxisCount, // 列数,即一行有几个子元素;
   this.mainAxisSpacing = 0.0, // 主轴方向上的空隙间距;
   this.crossAxisSpacing = 0.0, // 次轴方向上的空隙间距;
   this.childAspectRatio = 1.0, // 子元素的宽高比例
}

d. 示例代码

import 'package:flutter/material.dart'; // Material UI组件库

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

// 无状态控件显示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的组件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //标题
      theme: ThemeData(primarySwatch: Colors.blue), //主题色
      home: MyWidget(), // 返回一个Widget对象,用来定义当前应用打开的时候,所显示的界面
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new _MyWidgetState();
  }
}

class _MyWidgetState extends State<MyWidget> {

  ScrollController _controller = new ScrollController(); // 定义控制器

  @override
  void initState() {
    super.initState();
    // 设置监听方法
    _controller.addListener(() {
      print('_controller Listener');
      print(_controller.offset); // 打印滚动位置
    });
  }

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      scrollDirection: Axis.vertical, // 排列方向
      controller: _controller, // 设置控制器
      padding: EdgeInsets.all(10), // 内边距
      physics: new AlwaysScrollableScrollPhysics(), // 设置到边缘后的效果
      crossAxisCount: 3, // 每列3个
      childAspectRatio: 0.5,//宽高比为1:2
      mainAxisSpacing: 10, // 主轴、次轴方向间隔
      crossAxisSpacing: 10,
      children: getWidgetList(), // 表格数据(仅作demo展示,代码在下方)
    );
  }

  // GridView数据(仅作demo展示)
  List<String> litems = [
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "10",
    "11",
    "12",
    "13",
    "14",
    "15"
  ];

  List<Widget> getWidgetList() {
    return litems.map((item) => getItemContainer(item)).toList();
  }

  Widget getItemContainer(String item) {
    return Container(
      alignment: Alignment.center,
      child: Text(
        item,
        style: TextStyle(color: Colors.white, fontSize: 20),
      ),
      color: Colors.blue,
    );
  }
}

e. 示意图


类型3:GridView.extent

a. 特点

封装了SliverGridDelegateWithMaxCrossAxisExtent

b. 应用场景

子元素有最大宽度限制

c. 属性(构造函数)

 GridView.extent({
   Key key,
   Axis scrollDirection = Axis.vertical, // 列表的滚动方向,可选值:Axis的horizontal、vertical
   this.mainAxisSpacing = 0.0, // 主轴方向上的空隙间距;
   this.crossAxisSpacing = 0.0, // 次轴方向上的空隙间距;
   this.childAspectRatio = 1.0, // 子元素的宽高比例
   @required this.maxCrossAxisExtent, // 子元素的最大宽度可能是多少,然后计算得到合适的列宽
  // 示例:假如手机屏宽375,crossAxisSpacing值为0,
  // maxCrossAxisExtent值 = 125时,网格列数 = 3。因为125 * 3 = 375,刚好,每一列的宽度就是375/3。
  // maxCrossAxisExtent值 = 126时,网格列数 = 3。因为126 * 3 > 375,显示不下,每一列的宽度将是375/3。
  // maxCrossAxisExtent值为124时,网格列数 = 4。因为124 * 3 < 375,仍有多余,每一列的宽度将是375/4。
  })

d. 示例代码

import 'package:flutter/material.dart'; // Material UI组件库

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

// 无状态控件显示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的组件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //标题
      theme: ThemeData(primarySwatch: Colors.blue), //主题色
      home: MyWidget(), // 返回一个Widget对象,用来定义当前应用打开的时候,所显示的界面
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new _MyWidgetState();
  }
}

class _MyWidgetState extends State<MyWidget> {

  ScrollController _controller = new ScrollController(); // 定义控制器

  @override
  void initState() {
    super.initState();
    // 设置监听方法
    _controller.addListener(() {
      print('_controller Listener');
      print(_controller.offset); // 打印滚动位置
    });
  }

  @override
  Widget build(BuildContext context) {
    return GridView.extent(
      scrollDirection: Axis.vertical, // 排列方向
      controller: _controller, // 设置控制器
      padding: EdgeInsets.all(10), // 内边距
      physics: new AlwaysScrollableScrollPhysics(), // 设置到边缘后的效果
      maxCrossAxisExtent: 200, // 子元素宽度最大是200
      childAspectRatio: 0.5,//宽高比为1:2
      mainAxisSpacing: 10, // 主轴、次轴方向间隔
      crossAxisSpacing: 10,
      children: getWidgetList(), // 表格数据(仅作demo展示,代码在下方)
    );
  }

  // GridView数据(仅作demo展示)
  List<String> litems = [
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "10",
    "11",
    "12",
    "13",
    "14",
    "15"
  ];

  List<Widget> getWidgetList() {
    return litems.map((item) => getItemContainer(item)).toList();
  }

  Widget getItemContainer(String item) {
    return Container(
      alignment: Alignment.center,
      child: Text(
        item,
        style: TextStyle(color: Colors.white, fontSize: 20),
      ),
      color: Colors.blue,
    );
  }
}

e. 示意图

类型4:GridView.custom

a. 特点

可自定义SliverGridDelegate 和 SliverChildBuilderDelegate

b. 应用场景

更高程度的自定义监听 & 实现效果

c. 属性(构造函数)

 GridView.custom({
   Key key,
   Axis scrollDirection = Axis.vertical, // 列表的滚动方向,可选值:Axis的horizontal、vertical
   this.mainAxisSpacing = 0.0, // 主轴方向上的空隙间距;
   this.crossAxisSpacing = 0.0, // 次轴方向上的空隙间距;
   this.childAspectRatio = 1.0, // 子元素的宽高比例
   @required SliverGridDelegate gridDelegate, // 可传入自定义的SliverGridDelegate
  @required SliverChildDelegate childrenDelegate,  // 可传入自定义的SliverChildDelegate childrenDelegate
  })

d. 示例代码

/**
 *  导入库
 **/
import 'package:flutter/material.dart'; // Material UI组件库

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

// 无状态控件显示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的组件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //标题
      theme: ThemeData(primarySwatch: Colors.blue), //主题色
      home: MyWidget(), // 返回一个Widget对象,用来定义当前应用打开的时候,所显示的界面
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new _MyWidgetState();
  }
}

class _MyWidgetState extends State<MyWidget> {

  ScrollController _controller = new ScrollController(); // 定义控制器

  @override
  void initState() {
    super.initState();
    // 设置监听方法
    _controller.addListener(() {
      print('_controller Listener');
      print(_controller.offset); // 打印滚动位置
    });
  }

  @override
  Widget build(BuildContext context) {
    return GridView.custom(
      scrollDirection: Axis.vertical, // 排列方向
      controller: _controller, // 设置控制器
      padding: EdgeInsets.all(10), // 内边距
      physics: new AlwaysScrollableScrollPhysics(), // 设置到边缘后的效果

        gridDelegate:SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 3,// 列表数量是3
          childAspectRatio: 0.5,//宽高比为1:2
          mainAxisSpacing: 10, // 主轴、次轴方向间隔
          crossAxisSpacing: 10,
        ),

        childrenDelegate: MyGridChildrenDelegate( // 更高程度的自定义
              (BuildContext context, int i) {
                return Container(
                  alignment: Alignment.center,
                  child: Text(
                    litems[i],
                    style: TextStyle(color: Colors.white, fontSize: 20),
                  ),
                  color: Colors.blue,
                );
          },
          childCount: litems.length,
        ),


//      children: getWidgetList(), // 表格数据(仅作demo展示,代码在下方)
    );
  }

  // GridView数据(仅作demo展示)
  List<String> litems = [
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "10",
    "11",
    "12",
    "13",
    "14",
    "15"
  ];

  List<Widget> getWidgetList() {
    return litems.map((item) => getItemContainer(item)).toList();
  }

  Widget getItemContainer(String item) {
    return Container(
      alignment: Alignment.center,
      child: Text(
        item,
        style: TextStyle(color: Colors.white, fontSize: 20),
      ),
      color: Colors.blue,
    );
  }
}

/**
 * 自定义有SliverChildBuilderDelegate
 * 可实现对列表的监听
 */
class MyGridChildrenDelegate extends SliverChildBuilderDelegate {
  MyGridChildrenDelegate(
      Widget Function(BuildContext, int) builder, {
        int childCount,
        bool addAutomaticKeepAlive = true,
        bool addRepaintBoundaries = true,
      }) : super(builder,
      childCount: childCount,
      addAutomaticKeepAlives: addAutomaticKeepAlive,
      addRepaintBoundaries: addRepaintBoundaries);

  //监听列表
  // 在可见的列表中 显示的第一个位置和最后一个位置
  @override
  void didFinishLayout(int firstIndex, int lastIndex) {
    print('firstIndex: $firstIndex, lastIndex: $lastIndex');
  }

  // 判断添加进来的实例与之前的实例是否相同
  // 相同返回true;反之false
  // 可不重写,默认是true
  @override
  bool shouldRebuild(SliverChildBuilderDelegate oldDelegate) {
    // TODO: implement shouldRebuild
    print("oldDelegate$oldDelegate");
    return super.shouldRebuild(oldDelegate);
  }
}

e. 示意图

示意图

至此,关于GridView的使用讲解完毕。


4. 总结

本文全面介绍了Flutter GridView组件的使用,总结如下:

接下来推出的文章,我将继续讲解 Flutter 的相关知识,包括使用语法、实战等,感兴趣的读者可以继续关注我的博客哦:Carson_Ho的Android博客


请点赞!因为你们的赞同/鼓励是我写作的最大动力!

相关文章阅读
Android开发:最全面、最易懂的Android屏幕适配解决方案
Android开发:史上最全的Android消息推送解决方案
Android开发:最全面、最易懂的Webview详解
Android开发:JSON简介及最全面解析方法!
Android四大组件:Service服务史上最全面解析
Android四大组件:BroadcastReceiver史上最全面解析


欢迎关注Carson_Ho的简书!

不定期分享关于安卓开发的干货,追求短、平、快,但却不缺深度

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