[多图]手把手教你仿一个知乎日报Android客户端(三)主页面设计

各位朋友,从本篇文章和开始,手把手教你仿一个Android客户端就要正式开始探究怎样实现我们前面的那些需求了。在此开发我们将会使用git作为版本控制工具,并且将代码托管到github,好啦,废话少说,咱们开工。

一、创建项目

怎么创建项目大家应该都知道哈,我就不赘述了,在这里我的项目名为 “ZhiHudaily”,简单的翻译下就是知乎日报。
支持最低的SDK版本为 API 19也就是android 4.4
紧接着创建一个HomeActivity(MainActivity改名来的),顾名思义就是今天我们的主角— 当当当当 —Home页

二、配置CVS

具体的配置内容这里就不讲啦,各位可以参考下这篇文章

三、正式开始

依照我个人的习惯呢,在正式开始编写业务代码前有几件事情要做

1.编写BaseActivity
2.自己写一个Toolbar
3.更换默认主题

首先创建一个BaseActivit,记得在AndroidManifest.xml中注册哦

BaseActivity中主要是对Toolba的初始化以及对toolbar的左上角菜单按钮以及back按钮

重要的 BaseActivity代码


public class BaseActivity extends AppCompatActivity{
    public Toolbar toolbar;
    /**
     *
     * @param title 标题栏标题
     * @param type  标题类型,1为带菜单栏的标题栏,2为带back键的标题栏
     */
    public void setTitle(String title,int type){

        toolbar= (Toolbar) findViewById(R.id.toolbar);
        toolbar.setTitleTextColor(Color.WHITE);//标题字体颜色
        toolbar.setTitle(title);
        setSupportActionBar(toolbar);//设置为actionbar
        switch (type){
            case 1:
                toolbar.setNavigationIcon(R.drawable.menu);
                break;
            case 2:
                toolbar.setNavigationIcon(R.drawable.back);
                toolbar.setNavigationOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        finish();
                    }
                });
        }


    }


}

如果你愿意的话,甚至可以把Toast直接放到BaseActivity中单独写作一个方法,当要用到的时候,直接一行 showToast("");就搞定了

简单的 Toolbar的代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:background="@color/colorPrimary"
    android:layout_height="?attr/actionBarSize"/>
</LinearLayout>

我们创建好的项目在默认状态下会使用DarkActionBar(layout上面的一个蓝条),因为我们要用自己定义的toolbar,所以我们

修改style.xml

 <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

改为

 <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

此时我们可以对home页进行编辑,首先插入事先写好的toolbar,然后在activity中进行初始化以及设定

枯燥的 layout代码


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.administrator.zhihudaily.HomeActivity">
<include layout="@layout/toolbar"/>


</RelativeLayout>

枯燥的 HomeActivity代码

public class HomeActivity extends BaseActivity {
//记得,所有Activity都继承自BaseActivity

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

    //初始化布局
    private void initView(){
    
        setTitle("首页",1);//设置标题内容,该方法继承自父类,所以再写一次
    }
}

然后来看看样子

首页

添加开源库

这个项目中我们将会用到BGABanner库,以及v7包中的cardview,和Recycleview,以及图片加载库Gilde,网络访问库 Volley,Volley版本太多,所以我随意找了一个
在build.gradle中添加以下依赖

compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.android.support:cardview-v7:25.3.1'
compile 'cn.bingoogolapple:bga-banner:2.1.7@aar'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'eu.the4thfloor.volley:com.android.volley:2015.05.28'

设计item

枯燥的 info_item.xml代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item"
    android:background="#fff"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/item_headtitle"
        android:layout_width="match_parent"
        android:background="#fff"
        android:layout_height="30dp"
        android:visibility="gone"
        android:layout_marginTop="10dp"
        android:gravity="center|left"
        android:paddingLeft="10dp"
        android:text="头部"/>
    <android.support.v7.widget.CardView
        android:layout_marginTop="10dp"
        android:id="@+id/opencard"
        android:background="#fff"

        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:background="#fff"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <LinearLayout
                android:background="#fff"
                android:layout_weight="3"
                android:layout_width="300dp"
                android:gravity="center|left"
                android:orientation="vertical"
                android:layout_height="130dp">
                <TextView
                    android:id="@+id/item_title"
                    android:background="#fff"
                    android:layout_width="wrap_content"
                    android:padding="10dp"
                    android:textColor="#000"
                    android:textSize="18sp"
                    android:gravity="left"
                    android:text="标题"
                    android:layout_height="wrap_content" />
                <TextView
                    android:id="@+id/data"
                    android:layout_marginTop="10dp"
                    android:layout_marginLeft="10dp"
                    android:text="20170417"
                    android:visibility="gone"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content" />
            </LinearLayout>
            <ImageView
                android:layout_weight="1"
                android:layout_marginRight="5dp"
                android:id="@+id/item_image"
                android:layout_width="120dp"
                android:layout_height="120dp" />
        </LinearLayout>
    </android.support.v7.widget.CardView>
</LinearLayout>

此段代码中,包含了item的标题以及item的头部信息。

Recycleview可以看做是ListView的升级版,它性能更好,玩法也更多,既然要用到列表,那我们就需要有一个适配器,以及一个javabean类,用于生成列表中的新闻对象(?)

ItemBean

枯燥的 Item.class

package com.example.administrator.volleytest.UI.bean;

/**
 * Created by Administrator on 2017/4/17 0017.
 */

public class Item {
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getImgurl() {
        return imgurl;
    }

    public void setImgurl(String imgurl) {
        this.imgurl = imgurl;
    }

    public String getHeadtitle() {
        return headtitle;
    }

    public void setHeadtitle(String headtitle) {
        this.headtitle = headtitle;
    }

    String headtitle;//头部标题
    String id;//id
    String title;//文章标题
    String date;//日期
    String imgurl;//配图地址
}

懵逼的 InfoListAdapter.class

public class InfoListAdapter extends RecyclerView.Adapter<InfoListAdapter.InfoViewHolder> {
    private ArrayList<Item> mData;//用于储存数据
    private Context mContext;//上下文
    InfoViewHolder holder=null; //viewholde,可以提高recycleview的性能



    public  InfoListAdapter(ArrayList<Item> data,Context context) {

        //构造方法,用于接收上下文和展示数据

        this.mData = data;
        this.mContext=context;
    }


    @Override
    public InfoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        holder=new InfoViewHolder(LayoutInflater.from(mContext).inflate(R.layout.info_item,parent,false));

        return holder;
    }

    @Override
    public void onBindViewHolder(InfoViewHolder holder, int position) {
        //此方法内可以对布局中的控件进行操作

        holder.title.setText(mData.get(position).getTitle());//

        Glide.with(mContext).load(mData.get(position).getImgurl()).into(holder.img);
    }


    @Override
    public int getItemCount() {

        //获取数据长度

        return mData.size();
    }

    class InfoViewHolder extends RecyclerView.ViewHolder {
        //此部分我也难以用语言来解释,诸位可以搜索下网上各路大牛的详解
        //我也需要学习


        TextView title;//标题
        ImageView img;//显示的图片
        TextView headTitle;//头部标题

        public InfoViewHolder(View itemView) {
            super(itemView);

            title= (TextView) itemView.findViewById(R.id.item_title);
            img= (ImageView) itemView.findViewById(R.id.item_image);
            headTitle= (TextView) itemView.findViewById(R.id.item_headtitle);
        }
    }
}
    

适配器准备好后,我们要对HomeActivity和activity_main布局 做一些简单的修改用于测试适配器是否能够正常使用

首先,在activity_main.xml中添加RecycleView的控件,使其填满整个布局
activity_main.xml(部分)

<android.support.v7.widget.RecyclerView
    android:id="@+id/infolist"
    android:layout_marginTop="?attr/actionBarSize"
    android:layout_width="match_parent"
    android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>

然后在Activity中,我们需要对控件进行绑定,创建适配器以及添加模拟数据

将就能看的 HomeActiviy.java

public class HomeActivity extends BaseActivity {
    private RecyclerView mInfoList;//用于显示的列表

    private ArrayList<Item> mDatas;//用于储存数据

    private InfoListAdapter adapter;//适配器

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

    }

    private void initView() {
        //初始化页面
        setTitle("首页", 1);//设置标题
        mInfoList= (RecyclerView) findViewById(R.id.infolist);//绑定RecycleView
        mInfoList.setLayoutManager(new LinearLayoutManager(this));//设置布局管理器,你可以通过这个来决定你是要做一个Listview还是瀑布流
        adapter=new InfoListAdapter(mDatas,HomeActivity.this);//初始化适配器
        mInfoList.setAdapter(adapter);//为ReycleView设置适配器

    }

    private void  initDate(){
    //初始化数据
        mDatas=new ArrayList<>();
        
        //添加模拟数据
        for (int i='A';i<'z';i++){
            Item item=new Item();
            item.setTitle(""+(char)i);
            item.setImgurl("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1496110531&di=281ed2731cabceee7c851e5b2ca83a85&imgtype=jpg&er=1&src=http%3A%2F%2Fpic.58pic.com%2F58pic%2F13%2F15%2F64%2F44c58PICsni_1024.jpg");
            mDatas.add(item);
        }


    }
}

记得在AndroidManifest.xml中添加网络访问权限

    <uses-permission android:name="android.permission.INTERNET"/>

现在我们再看下效果

测试

大致效果就是这样,不过这个图片什么鬼

接下来就要考虑数据的问题,点开文档,我们直接看第三条 最新消息和第五条 过往消息

  1. 最新消息
    URL: http://news-at.zhihu.com/api/4/news/latest
    响应实例:
    {
    date: "20140523",
    stories: [
    {
    title: "中国古代家具发展到今天有两个高峰,一个两宋一个明末(多图)",
    ga_prefix: "052321",
    images: [
    "http://p1.zhimg.com/45/b9/45b9f057fc1957ed2c946814342c0f02.jpg"
    ],
    type: 0,
    id: 3930445
    },
    ...
    ],
    top_stories: [
    {
    title: "商场和很多人家里,竹制家具越来越多(多图)",
    image: "http://p2.zhimg.com/9a/15/9a1570bb9e5fa53ae9fb9269a56ee019.jpg",
    ga_prefix: "052315",
    type: 0,
    id: 3930883
    },
    ...
    ]
    }
    分析:
    date : 日期
    stories : 当日新闻
    title : 新闻标题
    images : 图像地址(官方 API 使用数组形式。目前暂未有使用多张图片的情形出现,曾见无 images 属性的情况,请在使用中注意 )
    ga_prefix : 供 Google Analytics 使用
    type : 作用未知
    id : url 与 share_url 中最后的数字(应为内容的 id)
    multipic : 消息是否包含多张图片(仅出现在包含多图的新闻中)
    top_stories : 界面顶部 ViewPager 滚动显示的显示内容(子项格式同上)(请注意区分此处的 image 属性与 stories 中的 images 属性)

我只贴出了第三条的数据,没有贴出第五条,因为第三条和第五条除了url后面带的参数不同,其返回形式是相同的
文档的作者已经将数据请求的链接以及返回数据的格式和 解释给出来了,下一步我们来写一个网络请求方法,将数据添加到ArrayList中

我们在HomeActivity中添加一个

初步展示的 HomeActivity.class

private int otherdate=0;//从今日算起,倒数第几天 eg:昨天 就是1 前天就是 2

private RequestQueue mQueue;
 private void  initDate(){
 
 
 //将此处之前的for循环插入虚拟数据删除
        mDatas=new ArrayList<>();
        getInfoFromNet();
    }

    private void getInfoFromNet(){
        //获取网络数据
        mQueue = Volley.newRequestQueue(this);
        
        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest("http://news.at.zhihu.com/api/4/news/before/" +    getDate(), null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                try {
                    
                    JSONArray list = null;
                    try {
                        list = response.getJSONArray("stories");
                        //获取返回数据的内容
                
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                        //开始解析数据
                    for (int i = 0; i < list.length(); i++) {
                        JSONObject item = list.getJSONObject(i);

                        JSONArray images = item.getJSONArray("images");
                        Item listItem = new Item();
                        //创建list中的每一个对象,并设置数据
                        listItem.setTitle(item.getString("title"));
                        listItem.setImgurl(images.getString(0));
                        listItem.setDate(getDate());
                        listItem.setId(item.getString("id"));
                        mDatas.add(listItem);
                    }
                     adapter.notifyDataSetChanged();//通知适配器 刷新数据啦 啊喂
                } catch (JSONException e) {
                    e.printStackTrace();
                }

            }
        }, new Response.ErrorListener() {
            //如果遇到异常,在这里通知用户
            @Override
            public void onErrorResponse(VolleyError error) {
            
                showToast("碰到了一点问题");
                //此处的showToast();是已经在BaseActivity中写好的,可以直接拿来用
            }
        });
        mQueue.add(jsonObjectRequest);//开始任务
    }



    private String getDate(){
            //获取当前需要加载的数据的日期
            Calendar c = Calendar.getInstance();
            c.setTime(new Date());
            c.add(Calendar.DAY_OF_MONTH, -otherdate);//otherdate天前的日子

            String date = new SimpleDateFormat("yyyyMMdd").format(c.getTime());
            //将日期转化为20170520这样的格式
            return date;

    }

我们再来看下效果

列表展示

然后和知乎日报对比下

知乎日报

可能有人要问了,Banner你吃了嘛?还有下面显示的内容和你这个不一样啊,还有那些今日热闻什么的,你到底会不会呀

嗯,我也注意到了,让我们来一项一项解决它

1.显示数据不准确

经过我的观察,虽然今天是2017年5月23日,但是去用20170523请求到的是昨天的数据,但是如果用20170524请求到的数据是不包含banner也就是“top_stories”字段,那么应该是请求的问题了
我们来对比下新内容和历史内容的请求链接
新的:http://news-at.zhihu.com/api/4/news/latest
历史内容:http://news.at.zhihu.com/api/4/news/before/20170523
嗯,刚才果然粗心大意了,那么代码又要改改。

更改后的代码 HomeActivity →getInfoFromNet()


 mQueue = Volley.newRequestQueue(this);
        String url=null;
        if (otherdate==0){
        //如果是今日就用最后的数据
            url="http://news-at.zhihu.com/api/4/news/latest";
        }else {
        //否则就是之前的判断流程
           url= "http://news.at.zhihu.com/api/4/news/before/" + getDate();
        }
        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, 
        //将此处之前的地址换为url参数
        ……
        //为了防止重复加载当前日的数据,我们需要让日子往后挪一天
        
          c.add(Calendar.DAY_OF_MONTH, -otherdate-1);//otherdate天前的日子
            ……
          

再来对比下

我们的日报

知乎日报

知乎日报

这样一来,最简单的数据问题解决了

2,Banner去哪儿了
我以前一直以为上面的banner是游离于listview之外的,知道我发现了headview这个东西,现在我们就要向recycleview中添加一个headview

先写一个headview的布局

headview.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="230dp"
    >
    <cn.bingoogolapple.bgabanner.BGABanner
        android:id="@+id/banner"
        app:banner_pageChangeDuration="1000"
        app:banner_pointAutoPlayAble="true"
        app:banner_tipTextSize="17sp"

        app:banner_pointTopBottomMargin="10dp"
        android:layout_width="match_parent"
        android:layout_height="230dp"/>
</LinearLayout>

对InfoListAdapter添加以下代码

修改InfoListAdapter

public class InfoListAdapter extends RecyclerView.Adapter<InfoListAdapter.InfoViewHolder> {
    private ArrayList<Item> mData;//用于储存数据
    private Context mContext;//上下文
    InfoViewHolder holder=null; //viewholde,可以提高recycleview的性能




    public  InfoListAdapter(ArrayList<Item> data,Context context) {

        //构造方法,用于接收上下文和展示数据

        this.mData = data;
        this.mContext=context;
    }

    @Override
    public InfoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    //这里进行过改动
        if (headView!=null && viewType==TYPE_HEADER) return new InfoViewHolder(headView);
        holder=new InfoViewHolder(LayoutInflater.from(mContext).inflate(R.layout.info_item,parent,false));
        return holder;
    }

    @Override
    public void onBindViewHolder(InfoViewHolder holder, int position) {
        //此方法内可以对布局中的控件进行操作
        //这里进行过改动
        if (getItemViewType(position)==TYPE_HEADER) return;
        final int pos=getRealPosition(holder);

        holder.title.setText(mData.get(pos).getTitle());//

        Glide.with(mContext).load(mData.get(pos).getImgurl()).into(holder.img);
    }


    @Override
    public int getItemCount() {

        //获取数据长度
        //这里进行过改动
        return headView==null? mData.size():mData.size()+1;
    }

    class InfoViewHolder extends RecyclerView.ViewHolder {
        //此部分我难以用语言来解释,诸位可以搜索下网上各路大牛的详解
        //我也需要学习


        TextView title;//标题
        ImageView img;//显示的图片
        TextView headTitle;//头部标题

        public InfoViewHolder(View itemView) {
            super(itemView);

            title= (TextView) itemView.findViewById(R.id.item_title);
            img= (ImageView) itemView.findViewById(R.id.item_image);
            headTitle= (TextView) itemView.findViewById(R.id.item_headtitle);
        }
    }
    
    
    //下面的是新添加的
    
    
    public static final int TYPE_HEADER = 0;//显示headvuiew
    public static final int TYPE_NORMAL = 1;//显示普通的item
    private View headView;//这家伙就是Banner

    public void setHeadView(View headView){
        this.headView=headView;
        notifyItemInserted(0);
    }

    public View getHeadView(){
        return headView;
    }

    @Override
    public int getItemViewType(int position) {
        if (headView==null)
            return TYPE_NORMAL;
        if (position==0)
            return TYPE_HEADER;
        return TYPE_NORMAL;
    }

    private int getRealPosition(RecyclerView.ViewHolder holder) {
        int position=holder.getLayoutPosition();
        return headView==null? position:position-1;
    }
}
    
    
    

向HomeActivity中添加以下代码

HomeActivity→initBanner();

  private ArrayList<Item> bannerList;//banner控件

    private ArrayList<String> titles;//存放banner中的标题

    private ArrayList<String> images;//存放banner中的图片

    private ArrayList<String> ids;//存放每一项的id

    private void initBanner() {
        //初始化banner
        titles=new ArrayList<>();
        ids=new ArrayList<>();
        images=new ArrayList<>();

        bannerList = new ArrayList<>();

        mQueue = Volley.newRequestQueue(this);
        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest("http://news-at.zhihu.com/api/4/news/latest", null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                try {
                    //解析banner中的数据
                    JSONArray topinfos = response.getJSONArray("top_stories");
                    Log.d("TAG", "onResponse: "+topinfos);
                    for (int i = 0; i < topinfos.length(); i++) {
                        JSONObject item = topinfos.getJSONObject(i);
                        Item item1 = new Item();
                        item1.setImgurl(item.getString("image"));
                        item1.setTitle(item.getString("title"));
                        item1.setId(item.getString("id"));
                        bannerList.add(item1);
                        titles.add(item1.getTitle());
                        images.add(item1.getImgurl());
                        ids.add(item1.getId());
                    }


                    setHeader(mInfoList, images, titles, ids);

                } catch (JSONException e) {
                    e.printStackTrace();
                }

            }
        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {

            }
        });
        mQueue.add(jsonObjectRequest);


    }

    private void setHeader(RecyclerView view, ArrayList<String> urls, ArrayList<String> titles, final ArrayList<String> ids) {
        View header = LayoutInflater.from(this).inflate(R.layout.headview, view, false);
        //找到banner所在的布局
        BGABanner banner = (BGABanner) header.findViewById(R.id.banner);
        //绑定banner
        banner.setAdapter(new BGABanner.Adapter<ImageView, String>() {


            @Override
            public void fillBannerItem(BGABanner banner, ImageView itemView, String model, int position) {
                Glide.with(HomeActivity.this)
                        .load(model)
                        .centerCrop()
                        .dontAnimate()
                        .into(itemView);
            }
        });
        banner.setDelegate(new BGABanner.Delegate() {
            @Override
            public void onBannerItemClick(BGABanner banner, View itemView, Object model, int position) {
             //此处可设置banner子项的点击事件

            }
        });
        banner.setData(urls, titles);
        adapter.setHeadView(header);//向适配器中添加banner
    }

我们再来看一次效果

主页大致效果

由于(不知道什么原因有限),这次就和大家交流这些,在下一篇博文中将会把我们在知乎日报上看到的日期头以及加载更多,刷新还有点击查看详细内容等功能实现出来。如果大家有不懂的欢迎在评论中说出来,如果我有哪部分表述的不准确,也希望能够得到指点。

愿与诸位同进步

谢谢。

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,737评论 25 707
  • 本文为作者原创,转载请注明出处[@大蘑菇的博客][1]图片托管服务由贴图库提供 作为一只网虫,肯定是经常泡在网络的...
    NOspy阅读 2,116评论 2 6
  • 仿照着知乎写了一套UI界面,结合着以前学的知识,一天就撸了出来,其实也没啥东西,就是有些没接触的地方踩了坑。 效果...
    hongjay阅读 11,161评论 17 117
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,628评论 18 139
  • 中国高等医学院校临床医学系目前把中医学作为必修课,由学术型资深中医师教授。所以,中国的西医临床医学毕业生对正统的中...
    YoungTsau阅读 572评论 0 1