Material Design入门

同一个产品经理出品的App, Android端的界面往往比不上iOS端. Android端界面整体色彩渲染的不协调, 一直受广大用户的诟病. Material Design的横空出世, 让Android端的使用者看到了希望--声称设计史上第一次超越了iOS端(作为一位iOS开发者,对此表示呵呵). 下面是Material Design实现的效果.

Material Design.gif

侧面抽屉效果的弹出, 以及详情界面顶部toolBar向上滚动时的渐变, 效果有没有很赞? 下面看一下具体实现.

首先, 需要在app的build.gradle文件中添加Material Design的支持库design, 其余的circleimageview, recyclerview, cardview, glide库, 项目中都会用到.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:26.+'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'com.android.support:design:26.+'
    compile 'de.hdodenhof:circleimageview:2.1.0'
    compile 'com.android.support:recyclerview-v7:26.+'
    compile 'com.android.support:cardview-v7:26.+'
    compile 'com.github.bumptech.glide:glide:4.0.0'

    annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0'
    testCompile 'junit:junit:4.12'
}
添加Toolbar

首先是将ActionBar替换成Toolbar,因为Toolbar才具有Materail Design效果. 修改路径app/src/main/res/values下的styles文件.

<resources>
    //主题是淡色, 陪衬设置成深色;
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        //主题是身色, 陪衬设置成淡色;
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="FruitActivityTheme" parent="AppTheme"></style>
</resources>

将样式改为Light.NoActionBar后,顶部的ActionBar就会被去掉. 然后在activity_main布局中添加Toolbar.

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    android:popupTheme="@style/ThemeOverlay.AppCompat.Light"
    app:title="Fruits"
    app:layout_scrollFlags="scroll|enterAlways|snap"
    ></android.support.v7.widget.Toolbar>

完成了以上工作, 就可以在MainActivity中使用了.

Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

ActionBar actionBar = getSupportActionBar();
if (actionBar != null){
    actionBar.setDisplayHomeAsUpEnabled(true);
    actionBar.setHomeAsUpIndicator(R.drawable.menu);
}

setDisplayHomeAsUpEnabled方法用来控制Toolbar顶部右边是否显示返回按钮, setHomeAsUpIndicator方法可以给Toolbar设置图片.

Toobar右边的按钮又是怎么添加的呢? res目录下新建Directory, 命名为menu, 在该文件下新建文件toolbar.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >

    <item
        android:id="@+id/backup"
        android:title="Backup"
        android:icon="@drawable/left"
        app:showAsAction="always"
        android:visible="true"
        android:enabled="true"/>
    <item
        android:id="@+id/delete"
        android:title="Delete"
        android:icon="@drawable/right"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/settings"
        android:title="settings"
        android:icon="@drawable/left"
        app:showAsAction="never"/>
</menu>

新建的布局包含了backup, delete, settings三个按钮. 其中showAsAction属性分别设置成always, ifRoom, never. 属性名称已经表明了界面效果.然后在MainActivity中的onCreateOptionsMenu方法中使用.

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
     super.onCreateOptionsMenu(menu);
     getMenuInflater().inflate(R.menu.toolbar, menu);
     return true;
 }
侧拉抽屉效果

该效果可以通过Material Design中的DrawerLayout实现.

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                android:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:title="Fruits"
                app:layout_scrollFlags="scroll|enterAlways|snap"
                ></android.support.v7.widget.Toolbar>
        </android.support.design.widget.AppBarLayout>

        <android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/recycler_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_behavior="@string/appbar_scrolling_view_behavior"></android.support.v7.widget.RecyclerView>
        </android.support.v4.widget.SwipeRefreshLayout>
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_margin="16dp"
            android:src="@drawable/newmsg"
            android:foregroundTint="#000"/>

    </android.support.design.widget.CoordinatorLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#abc"
        app:menu="@menu/nav_menu"
        app:headerLayout="@layout/nav_header"
        android:layout_gravity="start"
        >

    </android.support.design.widget.NavigationView>

</android.support.v4.widget.DrawerLayout>

DrawerLayout底层封装了一系列手势识别的方法. 使用时内部接收两个控件, 第一个CoordinatorLayout是主页面, 第二个NavigationView是侧滑时出现的页面.

CoordinatorLayout类似FrameLayout, 其内部的控件都会以父布局的左上角为参照. 不同的是CoordinatorLayout符合Material Design的设计理念, 可以自动识别CoordinatorLayout类型的控件并对它们进行有效调整, 提供更好的用户体验. 上面的例子中, 因为AppBarLayout和FloatingActionButton都是CoordinatorLayout的子类, 可以保证Toolbar不被SwipeRefreshLayout遮挡, FloatingActionButton也不会随着RecyclerView的上下滚动而出现偏移. NavigationView是Material Design抽屉效果中推荐的侧拉界面, 用于显示详情信息. 上面将名称为nav_menu和nav_header的布局文件分别放在了布局中的menu和layout文件夹下, 具体实现如下.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/nav_call"
            android:icon="@drawable/left"
            android:title="call"/>
        <item
            android:id="@+id/nav_friends"
            android:icon="@drawable/right"
            android:title="friends"/>
        <item
            android:id="@+id/nav_location"
            android:icon="@drawable/left"
            android:title="location"/>
        <item
            android:id="@+id/nav_mail"
            android:icon="@drawable/right"
            android:title="mail"/>
    </group>
</menu>

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="180dp"
    android:padding="10dp"
    android:background="?attr/colorPrimary">

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/icon_image"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:src="@drawable/aa"
        android:layout_centerInParent="true"/>
    <TextView
        android:id="@+id/mail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="Dog's mail: dog10@163.com"
        android:textColor="#fff"
        android:textSize="14sp"/>

    <TextView
        android:id="@+id/username"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@id/mail"
        android:text="Dog Yellow"
        android:textColor="#fff"
        android:textSize="14sp"/>
</RelativeLayout>

完成以上布局, 就可以在MainActivity中处理相关逻辑了.

public class MainActivity extends AppCompatActivity {


    private DrawerLayout drawerLayout;

    private SwipeRefreshLayout swipeRefreshLayout;

    private Fruit[] fruits = {
            new Fruit("Apple", R.drawable.apple),
            new Fruit("banana", R.drawable.banana),
            new Fruit("berray", R.drawable.berray),
            new Fruit("tomato", R.drawable.tomato),
    };

    private List<Fruit> fruitList = new ArrayList<>();

    private FruitAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        swipeRefreshLayout = (SwipeRefreshLayout)findViewById(R.id.swipe_refresh);
        swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                refreshFruits();
            }
        });

        Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        drawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
        NavigationView navigationView = (NavigationView)findViewById(R.id.nav_view);

        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null){

            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setHomeAsUpIndicator(R.drawable.menu);

        }
        navigationView.setCheckedItem(R.id.nav_call);
        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener(){
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                drawerLayout.closeDrawers();
                return true;
            }
        });

        FloatingActionButton fab = (FloatingActionButton)findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
//                Toast.makeText(MainActivity.this, "fabs clicked!", Toast.LENGTH_SHORT).show();
                Snackbar.make(view, "Data deleted", Snackbar.LENGTH_SHORT).setAction("Undo", new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        Toast.makeText(MainActivity.this, "Data restore", Toast.LENGTH_SHORT).show();
                    }
                }).show();
            }
        });

        initFruits();

        RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recycler_view);
        GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
        recyclerView.setLayoutManager(layoutManager);
        adapter = new FruitAdapter(fruitList);
        recyclerView.setAdapter(adapter);
    }

    private void refreshFruits(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    Thread.sleep(2000);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        initFruits();
                        adapter.notifyDataSetChanged();
                        swipeRefreshLayout.setRefreshing(false);
                    }
                });
            }
        }).start();
    }

    private void initFruits(){
        fruitList.clear();
        for (int i = 0; i < 50; i++){
            Random random = new Random();
            int index = random.nextInt(fruits.length);
            fruitList.add(fruits[index]);
        }
    }

    //menu的item最多显示2个,属性设置为never时,被折叠不显示.展开的大小是固定的.
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.toolbar, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case android.R.id.home:
                drawerLayout.openDrawer(GravityCompat.START);
                break;
            case R.id.backup:
                Toast.makeText(this, "Back up", Toast.LENGTH_SHORT).show();
                break;
            case R.id.delete:
                Toast.makeText(this, "Delete", Toast.LENGTH_SHORT).show();
                break;
            case R.id.settings:
                Toast.makeText(this, "Setting", Toast.LENGTH_SHORT).show();
                break;
        }
        return true;
    }
}

其中Fruit实体类和FruitAdapter是RecyclerView正常显示所需的java文件. 不明白的可以参照:ListView和RecyclerView

public class Fruit {
    private String name;

    private int imageId;

    public Fruit(String apple, int imageId) {
        this.name = apple;
        this.imageId = imageId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getImageId() {
        return imageId;
    }

    public void setImageId(int imageId) {
        this.imageId = imageId;
    }
}

public class FruitAdapter extends RecyclerView.Adapter <FruitAdapter.ViewHolder>{

    static class ViewHolder extends RecyclerView.ViewHolder{

        CardView cardView;
        ImageView fruitImage;
        TextView fruitName;

        public ViewHolder(View view){
            super(view);

            cardView = (CardView)view;
            fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
            fruitName = (TextView)view.findViewById(R.id.fruit_name);
        }
    }

    private List<Fruit> mFruits;
    private Context mContext;

    public FruitAdapter(List<Fruit> fruits){
        mFruits = fruits;
    }
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mContext == null){
            mContext = parent.getContext();
        }

        View view = LayoutInflater.from(mContext).inflate(R.layout.fruit_item, parent, false);

        final  ViewHolder holder = new ViewHolder(view);
        holder.cardView.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {

                int position = holder.getAdapterPosition();
                Fruit fruit = mFruits.get(position);
                Intent intent = new Intent(mContext, FruitActivity.class);
                intent.putExtra(FruitActivity.FRUIT_NAME, fruit.getName());
                intent.putExtra(FruitActivity.FRUIT_IMAGE_ID, fruit.getImageId());
                mContext.startActivity(intent);
            }
        });
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Fruit fruit = mFruits.get(position);
        holder.fruitName.setText(fruit.getName());
        Glide.with(mContext).load(fruit.getImageId()).into(holder.fruitImage);
    }

    @Override
    public int getItemCount() {
        return mFruits.size();
    }
}

RecycleView中的单元控件使用了Material Design中的CardView, 包含ImageView和TextView两个控件.

<?xml version="1.0" encoding="utf-8"?>

<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"

    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_margin="5dp"
    app:cardCornerRadius="4dp">
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/fruit_image"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:scaleType="centerCrop"/>

        <TextView
            android:id="@+id/fruit_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_margin="5dp"
            android:textSize="12sp"
            />
    </LinearLayout>

</android.support.v7.widget.CardView>

设置CardView中的Image时使用了Glide, 可以结合设备屏幕分辨率对图片的清晰度自动调整, 保证相对较好的渲染效果. 使用前需要导入相应的库, 具体设置可以参照文章开头.

Fruit详情页面

在FruitAdapter中给ViewHolder添加点击方法, 点击CardView的item后, 跳转到FruitActivity页面, 其布局文件如下:

<?xml version="1.0" encoding="utf-8"?>

<android.support.design.widget.CoordinatorLayout
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:fitsSystemWindows="true">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            android:fitsSystemWindows="true"
            >
            
            <ImageView
                android:id="@+id/fruit_image_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax"
                android:fitsSystemWindows="true"/>
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                ></android.support.v7.widget.Toolbar>
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.v7.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="15dp"
                android:layout_marginLeft="15dp"
                android:layout_marginRight="15dp"
                android:layout_marginTop="35dp"
                app:cardCornerRadius="4dp"></android.support.v7.widget.CardView>
            
                <TextView
                    android:id="@+id/fruit_content_text"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="10dp"/>

        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>

    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:src="@drawable/left"
        app:layout_anchor="@id/appBar"
        app:layout_anchorGravity="bottom|end"/>
</android.support.design.widget.CoordinatorLayout>

该页面包含3部分: 上面的AppBarLayout, 下面的NestedScrollView, 以及悬浮在页面的FloatingActionButton. 最后的FloatingActionButton的锚点依托在AppBarLayout的右下部.

使用CollapsingToolbarLayout可以实现随着ScrollView滚动的效果. 设置为layout_scrollFlags属性为'scroll|exitUntilCollapsed'后, CollapsingToolbarLayout就能根据ScrollView向上滚动的距离来决定内部控件的显示或者隐藏.为了满足Material Design设计, 需要将布局放在AppBarLayout当中.

Material Design当中允许修改顶部状态栏. 首先将符合CoordinatorLayout的父布局和子布局的fitsSystemWindows属性全部设置成true. 然后修改AppTheme为透明色. 由于Material Design是在Android5.0推出, 所以需要在res文件夹下新建目录values-v21对Android的不同版本进行适配. 在values-v21目录下新建styles.xml文件, 内容如下.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="FruitActivityTheme" parent="AppTheme">
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>
</resources>

NestedScrollView是符合Material Design标准的ScrollView, 使用方式也比较类似. 有了布局就可以在FruitActivity添加处理逻辑.

public class FruitActivity extends AppCompatActivity {


    public static final String FRUIT_NAME = "fruit_name";

    public static final String FRUIT_IMAGE_ID = "fruit_image_id";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fruit);

        Intent intent = getIntent();
        String fruitName = intent.getStringExtra(FRUIT_NAME);
        int fruitImageId = intent.getIntExtra(FRUIT_IMAGE_ID, 0);
        Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
        CollapsingToolbarLayout collapsingToolbarLayout = (CollapsingToolbarLayout)findViewById(R.id.collapsing_toolbar);
        ImageView fruitImageView = (ImageView)findViewById(R.id.fruit_image_view);
        TextView fruitContextText = (TextView)findViewById(R.id.fruit_content_text);
        setSupportActionBar(toolbar);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null){
            actionBar.setDisplayHomeAsUpEnabled(true);
        }
        collapsingToolbarLayout.setTitle(fruitName);
        Glide.with(this).load(fruitImageId).into(fruitImageView);
        String fruitContent = generateFruitContent(fruitName);
        fruitContextText.setText(fruitContent);
    }

    private String generateFruitContent(String fruitName){
        StringBuilder fruitContent = new StringBuilder();
        for (int i = 0; i < 500; i++){
            fruitContent.append(fruitName);
        }
        return fruitContent.toString();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch(item.getItemId()){
            case android.R.id.home:
                finish();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }
}
总结

Material Design是Android为了增强UI设计效果和提高用户体验而推荐的标准, 背后是统一的设计理念, 为标准繁多的Android界面设计吹来了一股清风. 上面的例子中利用Material Design中推出的组件替换了App的ActionBar为Toolbar,利用DrawerLayout实现了抽屉效果,并且在Fruit的详情页面,利用CollapsingToolbarLayout实现了Toolbar随NestedScrollView滚动而变化. 相信经过以上实践, 能够对Material Design的理解能够更加深入. 也希望在App的开发中能够践行Material Design的设计理念.

GitHub源码

喜欢和关注都是对我的支持和鼓励~

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

推荐阅读更多精彩内容