• 安卓开发笔记——打造属于自己的博客园APP(四)


      在上篇文章《安卓开发笔记——打造属于自己的博客园APP(三)》中,我们对博客文章的详情页和评论页进行了实现,慢慢的一个APP已经出现雏形了,当然这只是完成了"表面效果",要真正做好一个APP并不是一件很轻松的事情,有很多细节需要我们一点一滴的去完善。

      好了,来讲下今天要完成的效果,在优化了之前部分代码的前提下,今天来说下关于博客搜索和博客详情页的实现,依旧国际惯例,来看下效果图:(动态图片比较大,加载需要点时间)

      效果比较简单,很多东西我们还是可以复用之前的代码,毕竟这种列表长得都差不多,然后大致功能基本完成了,从下篇文章开始可以引入我们的数据库了,开始实现缓存操作。

    1、关于搜索页面的实现:

      很简单,分成两部分,上面一个EditText,下面一个RecyclerView,当我们刚进入页面的时候默认展示博客园给我们的推荐用户,当搜索的时候更新列表数据。

      这里是关于博客园推荐用户的接口: http://wcf.open.cnblogs.com/blog/bloggers/recommend/{PAGEINDEX}/{PAGESIZE} {PAGEINDEX}代表页码,{PAGESIZE}代表每页展示的条数

    这里是搜索页面的主布局文件:

     1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     xmlns:tools="http://schemas.android.com/tools"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent"
     5     android:orientation="vertical">
     6 
     7 
     8     <!--ToolBar-->
     9     <include layout="@layout/activity_toolbar" />
    10 
    11     <LinearLayout
    12         android:layout_width="match_parent"
    13         android:layout_height="wrap_content"
    14         android:background="@color/md_green_700"
    15         android:paddingBottom="10dp"
    16         android:paddingLeft="20dp"
    17         android:paddingRight="20dp"
    18         android:paddingTop="10dp">
    19 
    20         <RelativeLayout
    21             android:layout_width="match_parent"
    22             android:layout_height="40dp"
    23             android:background="@drawable/bg_search"
    24             android:gravity="center_vertical">
    25 
    26             <ImageButton
    27                 android:id="@+id/ib_search"
    28                 android:layout_width="wrap_content"
    29                 android:layout_height="wrap_content"
    30                 android:layout_alignParentRight="true"
    31                 android:background="@drawable/bt_search_selector" />
    32 
    33             <EditText
    34                 android:id="@+id/et_text"
    35                 android:layout_width="match_parent"
    36                 android:layout_height="wrap_content"
    37                 android:layout_toLeftOf="@id/ib_search"
    38                 android:background="@null"
    39                 android:hint="搜索其他博客" />
    40         </RelativeLayout>
    41     </LinearLayout>
    42 
    43     <FrameLayout
    44         android:layout_width="match_parent"
    45         android:layout_height="match_parent">
    46 
    47         <android.support.v7.widget.RecyclerView
    48             android:id="@+id/rv_view"
    49             android:layout_width="match_parent"
    50             android:layout_height="match_parent"
    51             android:background="@color/md_grey_200"
    52             android:scrollbars="none" />
    53 
    54         <com.lcw.rabbit.myblog.view.MyProgressBar
    55             android:id="@+id/progressbar"
    56             android:layout_width="match_parent"
    57             android:layout_height="20dp"
    58             android:layout_gravity="bottom"
    59             android:visibility="gone" />
    60     </FrameLayout>
    61 </LinearLayout>
    activity_search.xml

    这里是下面RecyclerView列表的Item布局:

     1 <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
     2     xmlns:app="http://schemas.android.com/apk/res-auto"
     3     android:layout_width="match_parent"
     4     android:layout_height="wrap_content"
     5     android:layout_margin="8dp"
     6     android:gravity="center"
     7     app:cardCornerRadius="6dp">
     8 
     9     <include layout="@layout/recyclerview_item_authorlist_content" />
    10 
    11 </android.support.v7.widget.CardView>
    recyclerview_item_authorlist.xml

    这里是Item布局的详细:

      1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      2     xmlns:app="http://schemas.android.com/apk/res-auto"
      3     android:layout_width="match_parent"
      4     android:layout_height="wrap_content"
      5     android:background="?android:selectableItemBackground"
      6     android:orientation="horizontal"
      7     android:padding="3dp">
      8     <!--头像-->
      9     <com.makeramen.roundedimageview.RoundedImageView
     10         android:id="@+id/iv_userhead"
     11         android:layout_width="60dp"
     12         android:layout_height="60dp"
     13         android:layout_gravity="center_vertical"
     14         android:layout_marginRight="5dp"
     15         android:src="@mipmap/avatar_default"
     16         app:riv_border_color="#ffffff"
     17         app:riv_border_width="2dip"
     18         app:riv_corner_radius="30dip"
     19         app:riv_mutate_background="true"
     20         app:riv_oval="true"
     21         app:riv_tile_mode="repeat" />
     22     <!--信息内容-->
     23     <LinearLayout
     24         android:layout_width="0dp"
     25         android:layout_height="wrap_content"
     26         android:layout_marginLeft="3dp"
     27         android:layout_weight="1"
     28         android:orientation="vertical">
     29 
     30         <TextView
     31             android:id="@+id/tv_name"
     32             android:layout_width="match_parent"
     33             android:layout_height="wrap_content"
     34             android:layout_marginTop="2dp"
     35             android:layout_weight="1"
     36             android:ellipsize="end"
     37             android:singleLine="true"
     38             android:text="测试标题"
     39             android:textColor="@color/md_grey_900"
     40             android:textSize="16sp"
     41             android:textStyle="bold" />
     42 
     43         <TextView
     44             android:id="@+id/tv_url"
     45             android:layout_width="match_parent"
     46             android:layout_height="wrap_content"
     47             android:layout_weight="1"
     48             android:maxLines="3"
     49             android:text="浏览器类型判断方法有两种:根据浏览器特性来判断根据来检测具体使用哪种方法要看具体需求的场景场景一:为了让用户有较流畅完整的体验,在站点提示用户使用或者,这种场景对浏览器类型的判断并非特别严格,可以使用检测的方法。(因为很多浏览器厂商会篡改标识)。场景二...."
     50             android:textSize="14sp" />
     51 
     52         <LinearLayout
     53             android:layout_width="match_parent"
     54             android:layout_height="match_parent"
     55             android:layout_margin="1dp"
     56             android:layout_weight="1"
     57             android:orientation="horizontal">
     58 
     59             <TextView
     60                 android:layout_width="wrap_content"
     61                 android:layout_height="match_parent"
     62                 android:gravity="center_vertical"
     63                 android:text="博文数:"
     64                 android:textColor="@color/md_grey_500"
     65                 android:textSize="12sp" />
     66 
     67             <TextView
     68                 android:id="@+id/tv_sum"
     69                 android:layout_width="wrap_content"
     70                 android:layout_height="match_parent"
     71                 android:layout_marginRight="5dp"
     72                 android:gravity="center_vertical"
     73                 android:textColor="@color/md_grey_500"
     74                 android:textSize="12sp" />
     75 
     76             <TextView
     77                 android:layout_width="wrap_content"
     78                 android:layout_height="match_parent"
     79                 android:gravity="center_vertical"
     80                 android:text="最后更新:"
     81                 android:textColor="@color/md_grey_500"
     82                 android:textSize="12sp" />
     83 
     84             <TextView
     85                 android:id="@+id/tv_time"
     86                 android:layout_width="wrap_content"
     87                 android:layout_height="match_parent"
     88                 android:layout_marginRight="5dp"
     89                 android:textColor="@color/md_grey_500"
     90                 android:textSize="12sp" />
     91 
     92         </LinearLayout>
     93 
     94     </LinearLayout>
     95 
     96     <!--操作按钮-->
     97     <ImageButton
     98         android:id="@+id/ib_more"
     99         android:layout_width="25dp"
    100         android:layout_height="match_parent"
    101         android:background="?android:selectableItemBackground"
    102         android:gravity="center_horizontal"
    103         android:src="@mipmap/triangle" />
    104 </LinearLayout>
    recyclerview_item_authorlist_content.xml

    关于博客园推荐博客的接口数据XML解析,和我们之前在做博文列表数据的解析都是一样的,只不过是XML的节点不同,这里贴出解析代码:

      1 package com.lcw.rabbit.myblog.parser;
      2 
      3 import com.lcw.rabbit.myblog.entity.Author;
      4 
      5 import org.xmlpull.v1.XmlPullParser;
      6 import org.xmlpull.v1.XmlPullParserException;
      7 import org.xmlpull.v1.XmlPullParserFactory;
      8 
      9 import java.io.IOException;
     10 import java.io.InputStream;
     11 import java.util.ArrayList;
     12 import java.util.List;
     13 
     14 /**
     15  * 对博客作者(列表)xml数据的解析
     16  * Created by Lichenwei
     17  * Date: 2015-08-17
     18  * Time: 13:32
     19  */
     20 public class AuthorListXmlParser {
     21 
     22 
     23     /**
     24      * 用于解析博客作者(列表)的xml,返回Avatar的List集合对象
     25      *
     26      * @param inputStream
     27      * @param encode
     28      * @return
     29      * @throws XmlPullParserException
     30      * @throws IOException
     31      */
     32     public static List<Author> getListAuthor(InputStream inputStream, String encode) throws XmlPullParserException, IOException {
     33 
     34         List<Author> mAuthors = null;
     35         Author mAuthor = null;
     36 
     37         //获取XmlPullParser实例
     38         XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
     39         XmlPullParser parser = factory.newPullParser();
     40         parser.setInput(inputStream, encode);
     41         //获取解析事件
     42         int eventType = parser.getEventType();
     43         //当xml文档未到尾端时
     44         while (eventType != XmlPullParser.END_DOCUMENT) {
     45             switch (eventType) {
     46                 //解析根标签的时候,实例化集合
     47                 case XmlPullParser.START_DOCUMENT:
     48                     mAuthors = new ArrayList<Author>();
     49                     mAuthor = new Author();
     50 
     51                     break;
     52                 case XmlPullParser.START_TAG:
     53                     //当解析到entry标签的时候,实例化Avatar对象
     54                     if ("entry".equals(parser.getName())) {
     55                         mAuthor = new Author();
     56                     }
     57                     if ("id".equals(parser.getName())) {
     58                         parser.next();
     59                         mAuthor.setAuthorUrl(parser.getText());
     60                     } else if ("title".equals(parser.getName())) {
     61                         parser.next();
     62                         if (parser.getText().indexOf("博客园") == -1) {
     63                             mAuthor.setAuthorName(parser.getText());
     64                         }
     65                     } else if ("avatar".equals(parser.getName())) {
     66                         parser.next();
     67                         mAuthor.setAuthorPic(parser.getText());
     68                     } else if ("blogapp".equals(parser.getName())) {
     69                         parser.next();
     70                         mAuthor.setBlogApp(parser.getText());
     71                     } else if ("postcount".equals(parser.getName())) {
     72                         parser.next();
     73                         mAuthor.setBlogCount(parser.getText());
     74                     } else if ("updated".equals(parser.getName())) {
     75                         parser.next();
     76                         //区分日期格式
     77                         if (parser.getText().indexOf("+") != -1) {
     78                             mAuthor.setUpdated(parser.getText());
     79                         }
     80 
     81                     }
     82                     break;
     83                 case XmlPullParser.END_TAG:
     84                     //当解析到entry标签结束的时候添加入Avatar集合,清空Avatar对象
     85                     if ("entry".equals(parser.getName())) {
     86                         mAuthors.add(mAuthor);
     87                         mAuthor = null;
     88                     }
     89                     break;
     90 
     91             }
     92             //手动跳转第一次遍历
     93             eventType = parser.next();
     94         }
     95 
     96 
     97         return mAuthors;
     98 
     99     }
    100 
    101 }

      这里是搜索主页面代码,当我们点击搜索按钮的时候,获取输入框的博客关键字,进行搜索,将得到的数据更新数据源重新展示在RecyclerView。

      关于搜索博客关键字的接口:http://wcf.open.cnblogs.com/blog/bloggers/search?t={TERM} {TERM}代表作者名(多关键字匹配),搜索到的XML数据信息刚好又和我们前面的推荐博客内容格式一致,所以我们可以复用之前的解析工具类,然后一样具备上拉刷新和下拉加载功能:

      1 package com.lcw.rabbit.myblog;
      2 
      3 import android.content.Intent;
      4 import android.os.Bundle;
      5 import android.support.v7.app.AppCompatActivity;
      6 import android.support.v7.widget.LinearLayoutManager;
      7 import android.support.v7.widget.RecyclerView;
      8 import android.support.v7.widget.Toolbar;
      9 import android.view.View;
     10 import android.widget.EditText;
     11 import android.widget.ImageButton;
     12 import android.widget.Toast;
     13 
     14 import com.afollestad.materialdialogs.MaterialDialog;
     15 import com.android.volley.Request;
     16 import com.android.volley.Response;
     17 import com.android.volley.VolleyError;
     18 import com.android.volley.toolbox.StringRequest;
     19 import com.lcw.rabbit.myblog.adapter.AuthorListAdapter;
     20 import com.lcw.rabbit.myblog.entity.Author;
     21 import com.lcw.rabbit.myblog.entity.Blog;
     22 import com.lcw.rabbit.myblog.parser.AuthorListXmlParser;
     23 import com.lcw.rabbit.myblog.utils.VolleyRequestQueueManager;
     24 import com.lcw.rabbit.myblog.view.MyProgressBar;
     25 import com.mugen.Mugen;
     26 import com.mugen.MugenCallbacks;
     27 import com.mugen.attachers.BaseAttacher;
     28 
     29 import org.xmlpull.v1.XmlPullParserException;
     30 
     31 import java.io.ByteArrayInputStream;
     32 import java.io.IOException;
     33 import java.util.ArrayList;
     34 import java.util.List;
     35 
     36 /**
     37  * 博客搜索页
     38  */
     39 public class SearchActivity extends AppCompatActivity {
     40 
     41     //界面控件
     42     private Toolbar mToolbar;
     43     private EditText mEditText;
     44     private ImageButton mImageButton;
     45     private RecyclerView mRecyclerView;
     46     private MaterialDialog materialDialog;
     47     //无限滚动
     48     private BaseAttacher mBaseAttacher;
     49     private MyProgressBar myProgressBar;
     50 
     51     //数据源
     52     private AuthorListAdapter mAuthorListAdapter;
     53     private List<Author> mAuthors;
     54 
     55     //标志变量
     56     private boolean isLoading = false;
     57     private int currentPage = 1;
     58 
     59 
     60     @Override
     61     protected void onCreate(Bundle savedInstanceState) {
     62         super.onCreate(savedInstanceState);
     63         setContentView(R.layout.activity_search);
     64         initView();
     65         initData();
     66         initAction();
     67     }
     68 
     69     /**
     70      * 设置控件监听
     71      */
     72     private void initAction() {
     73         //设置无限滚动,上拉加载
     74         mBaseAttacher = Mugen.with(mRecyclerView, new MugenCallbacks() {
     75             @Override
     76             public void onLoadMore() {
     77                 //加载更多
     78                 isLoading = true;
     79                 mBaseAttacher.setLoadMoreEnabled(false);
     80                 myProgressBar.setVisibility(View.VISIBLE);
     81                 getData((currentPage + 1), 10);
     82             }
     83 
     84             @Override
     85             public boolean isLoading() {
     86                 return isLoading;
     87             }
     88 
     89             @Override
     90             public boolean hasLoadedAllItems() {
     91                 return isLoading;
     92             }
     93         }).start();
     94         //离底部一项的时候加载更多
     95         mBaseAttacher.setLoadMoreOffset(1);
     96 
     97         //点击搜索
     98         mImageButton.setOnClickListener(new View.OnClickListener() {
     99             @Override
    100             public void onClick(View v) {
    101                 materialDialog = new MaterialDialog.Builder(SearchActivity.this).content("内容加载中..").progress(true, 0).show();
    102                 String name = mEditText.getText().toString();
    103                 getDataByName(name.trim());
    104             }
    105         });
    106 
    107         //设置RecyclerView点击监听
    108         mAuthorListAdapter.setRecyclerViewListener(new AuthorListAdapter.RecyclerViewListener() {
    109             @Override
    110             public void setOnclickListener(View view, String value) {
    111                 //封装Bolg对象传递
    112                 Blog blog = new Blog();
    113                 blog.setBlogApp(mAuthors.get(Integer.parseInt(value)).getBlogApp());
    114                 blog.setAuthorName(mAuthors.get(Integer.parseInt(value)).getAuthorName());
    115                 Intent intent = new Intent();
    116                 intent.setClass(SearchActivity.this, AuthorActivity.class);
    117                 Bundle bundle = new Bundle();
    118                 bundle.putSerializable("blog", blog);
    119                 intent.putExtras(bundle);
    120                 startActivity(intent);
    121             }
    122         });
    123     }
    124 
    125     /**
    126      * 初始化控件
    127      */
    128     private void initView() {
    129         //ToolBar
    130         mToolbar = (Toolbar) findViewById(R.id.activity_toolbar);
    131         setSupportActionBar(mToolbar);
    132         //需要放在setSupportActionBar后设置
    133         mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
    134             @Override
    135             public void onClick(View v) {
    136                 finish();
    137             }
    138         });
    139         getSupportActionBar().setTitle("博客搜索");
    140         getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    141 
    142         //输入搜索
    143         mEditText = (EditText) findViewById(R.id.et_text);
    144         mImageButton = (ImageButton) findViewById(R.id.ib_search);
    145         //列表
    146         mRecyclerView = (RecyclerView) findViewById(R.id.rv_view);
    147         mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    148         //当高度确定,提高效率
    149         mRecyclerView.setHasFixedSize(true);
    150         //友好提醒
    151         myProgressBar = (MyProgressBar) findViewById(R.id.progressbar);
    152 
    153     }
    154 
    155     /**
    156      * 初始化数据
    157      */
    158     private void initData() {
    159         //显示下拉刷新样式
    160         mAuthors = new ArrayList<Author>();
    161         //设置空数据
    162         mAuthorListAdapter = new AuthorListAdapter(this, mAuthors);
    163         mRecyclerView.setAdapter(mAuthorListAdapter);
    164         getData(1, 10);
    165     }
    166 
    167     /**
    168      * 根据博主昵称搜索博客
    169      *
    170      * @param name
    171      */
    172     public void getDataByName(String name) {
    173         String url = "http://wcf.open.cnblogs.com/blog/bloggers/search?t=" + name;
    174         StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
    175             @Override
    176             public void onResponse(String s) {
    177                 try {
    178                     ByteArrayInputStream inputStream = new ByteArrayInputStream(s.getBytes());
    179                     List<Author> authors = AuthorListXmlParser.getListAuthor(inputStream, "utf-8");
    180                     if (authors.size() != 0) {
    181                         //清空之前的数据预防重复加载
    182                         mAuthors.clear();
    183                         for (Author author : authors) {
    184                             mAuthors.add(author);
    185                         }
    186 
    187                         if (mAuthorListAdapter == null) {
    188                             mAuthorListAdapter = new AuthorListAdapter(SearchActivity.this, mAuthors);
    189                             mRecyclerView.setAdapter(mAuthorListAdapter);
    190                         } else {
    191                             //通知adatper数据源更新
    192                             mAuthorListAdapter.refreshData(mAuthors);
    193                         }
    194 
    195                         materialDialog.dismiss();
    196                     } else {
    197                         //如果匹配不到关键字
    198                         Toast.makeText(SearchActivity.this, "找不到相关用户,请重新搜索", Toast.LENGTH_SHORT).show();
    199                         materialDialog.dismiss();
    200                     }
    201                 } catch (XmlPullParserException e) {
    202                     e.printStackTrace();
    203                 } catch (IOException e) {
    204                     e.printStackTrace();
    205                 }
    206             }
    207         }, new Response.ErrorListener() {
    208             @Override
    209             public void onErrorResponse(VolleyError volleyError) {
    210                 Toast.makeText(SearchActivity.this, volleyError.getMessage(), Toast.LENGTH_SHORT).show();
    211             }
    212         });
    213 
    214         VolleyRequestQueueManager.addRequest(request, "getAuthorList");
    215 
    216     }
    217 
    218 
    219     /**
    220      * 获取推荐数据
    221      *
    222      * @param page
    223      * @param num
    224      */
    225     public void getData(final int page, int num) {
    226         this.currentPage = page;
    227         String url = "http://wcf.open.cnblogs.com/blog/bloggers/recommend/" + page + "/" + num;
    228         StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
    229             @Override
    230             public void onResponse(String s) {
    231                 try {
    232                     ByteArrayInputStream inputStream = new ByteArrayInputStream(s.getBytes());
    233                     List<Author> authors = AuthorListXmlParser.getListAuthor(inputStream, "utf-8");
    234                     if (page == 1) {
    235                         //清空之前的数据预防重复加载
    236                         mAuthors.clear();
    237                     }
    238                     for (Author author : authors) {
    239                         mAuthors.add(author);
    240                     }
    241 
    242                     if (mAuthorListAdapter == null) {
    243                         mAuthorListAdapter = new AuthorListAdapter(SearchActivity.this, mAuthors);
    244                         mRecyclerView.setAdapter(mAuthorListAdapter);
    245                     } else {
    246                         //通知adatper数据源更新
    247                         mAuthorListAdapter.refreshData(mAuthors);
    248                     }
    249 
    250                     isLoading = false;
    251                     mBaseAttacher.setLoadMoreEnabled(true);
    252                     myProgressBar.setVisibility(View.GONE);
    253 
    254                 } catch (XmlPullParserException e) {
    255                     e.printStackTrace();
    256                 } catch (IOException e) {
    257                     e.printStackTrace();
    258                 }
    259             }
    260         }, new Response.ErrorListener() {
    261             @Override
    262             public void onErrorResponse(VolleyError volleyError) {
    263                 Toast.makeText(SearchActivity.this, volleyError.getMessage(), Toast.LENGTH_SHORT).show();
    264             }
    265         });
    266 
    267         VolleyRequestQueueManager.addRequest(request, "getAuthorList");
    268 
    269 
    270     }
    271 
    272 }

    这里是博客列表的适配器类,和之前的博文列表一样,我们需要自己添加点击监听,再点击Item项的时候将Blog对象传递:

      1 package com.lcw.rabbit.myblog.adapter;
      2 
      3 import android.content.Context;
      4 import android.content.res.Resources;
      5 import android.graphics.Bitmap;
      6 import android.graphics.BitmapFactory;
      7 import android.support.v7.widget.RecyclerView;
      8 import android.view.LayoutInflater;
      9 import android.view.View;
     10 import android.view.ViewGroup;
     11 import android.widget.ImageButton;
     12 import android.widget.TextView;
     13 
     14 import com.lcw.rabbit.myblog.R;
     15 import com.lcw.rabbit.myblog.entity.Author;
     16 import com.lcw.rabbit.myblog.utils.ImageCacheManager;
     17 import com.lcw.rabbit.myblog.utils.TimeUtil;
     18 import com.makeramen.roundedimageview.RoundedImageView;
     19 
     20 import java.util.List;
     21 
     22 /**
     23  * 推荐博主列表适配器
     24  * Created by Lichenwei
     25  * Date: 2015-08-16
     26  * Time: 22:34
     27  */
     28 public class AuthorListAdapter extends RecyclerView.Adapter<AuthorListAdapter.RecyclerViewViewHolder> {
     29 
     30     private Context mContext;
     31     private List<Author> mAuthors;
     32 
     33     public AuthorListAdapter(Context context, List<Author> authors) {
     34         this.mContext = context;
     35         this.mAuthors = authors;
     36     }
     37 
     38     /**
     39      * 设置新的数据源,提醒adatper更新
     40      *
     41      * @param authors
     42      */
     43     public void refreshData(List<Author> authors) {
     44         this.mAuthors = authors;
     45         this.notifyDataSetChanged();
     46     }
     47 
     48     /**
     49      * 自定义点击回调接口
     50      */
     51     public interface RecyclerViewListener {
     52         void setOnclickListener(View view, String value);
     53     }
     54 
     55     private RecyclerViewListener mRecyclerViewListener;
     56 
     57     /**
     58      * 提供setter方法
     59      *
     60      * @param recyclerViewListener
     61      */
     62     public void setRecyclerViewListener(RecyclerViewListener recyclerViewListener) {
     63         this.mRecyclerViewListener = recyclerViewListener;
     64     }
     65 
     66 
     67     /**
     68      * 创建ViewHolder
     69      *
     70      * @param viewGroup
     71      * @param i
     72      * @return
     73      */
     74     @Override
     75     public RecyclerViewViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
     76         View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recyclerview_item_authorlist, viewGroup, false);
     77         return new RecyclerViewViewHolder(view);
     78     }
     79 
     80     /**
     81      * 根据资源ID返回Bitmap对象
     82      *
     83      * @param resId
     84      * @return
     85      */
     86     public Bitmap getBitmapFromRes(int resId) {
     87         Resources res = mContext.getResources();
     88         return BitmapFactory.decodeResource(res, resId);
     89 
     90     }
     91 
     92     /**
     93      * 绑定数据
     94      *
     95      * @param viewholder
     96      * @param i
     97      */
     98     @Override
     99     public void onBindViewHolder(RecyclerViewViewHolder viewholder, int i) {
    100         //设置头像
    101         if (mAuthors.get(i).getAuthorPic() != null && !"".equals(mAuthors.get(i).getAuthorPic())) {
    102             ImageCacheManager.loadImage(mAuthors.get(i).getAuthorPic(), viewholder.mUserhead, getBitmapFromRes(R.mipmap.avatar_default), getBitmapFromRes(R.mipmap.avatar_default));
    103         } else {
    104             viewholder.mUserhead.setImageResource(R.mipmap.avatar_default);
    105         }
    106         viewholder.mName.setText(mAuthors.get(i).getAuthorName());
    107         viewholder.mUrl.setText(mAuthors.get(i).getAuthorUrl());
    108         viewholder.mSum.setText(mAuthors.get(i).getBlogCount());
    109         viewholder.mTime.setText(mAuthors.get(i).getUpdated());
    110         //处理日期特殊格式
    111         String date = TimeUtil.DateToChineseString(TimeUtil.ParseUTCDate(mAuthors.get(i).getUpdated()));
    112         viewholder.mTime.setText(date);
    113 
    114         //设置点击监听
    115         viewholder.itemView.setTag(i);
    116         viewholder.mMore.setTag(i);
    117         viewholder.itemView.setOnClickListener(new ItemClick());
    118         viewholder.mMore.setOnClickListener(new ItemClick());
    119     }
    120 
    121     @Override
    122     public int getItemCount() {
    123         return mAuthors.size();
    124     }
    125 
    126     /**
    127      * 自定义ViewHolder
    128      */
    129     public static class RecyclerViewViewHolder extends RecyclerView.ViewHolder {
    130         private RoundedImageView mUserhead;
    131         private TextView mName;
    132         private TextView mUrl;
    133         private TextView mTime;
    134         private TextView mSum;
    135         private ImageButton mMore;
    136 
    137         public RecyclerViewViewHolder(View view) {
    138             super(view);
    139             mUserhead = (RoundedImageView) view.findViewById(R.id.iv_userhead);
    140             mName = (TextView) view.findViewById(R.id.tv_name);
    141             mUrl = (TextView) view.findViewById(R.id.tv_url);
    142             mTime = (TextView) view.findViewById(R.id.tv_time);
    143             mSum = (TextView) view.findViewById(R.id.tv_sum);
    144             mMore = (ImageButton) view.findViewById(R.id.ib_more);
    145 
    146         }
    147 
    148     }
    149 
    150 
    151     /**
    152      * 点击事件实现类
    153      */
    154     public class ItemClick implements View.OnClickListener {
    155         @Override
    156         public void onClick(View v) {
    157             if (mRecyclerViewListener != null) {
    158                 mRecyclerViewListener.setOnclickListener(v, String.valueOf(v.getTag()));
    159             }
    160         }
    161     }
    162 }

    2、关于博客首页的实现:

      页面的整体结构还是类似,上半部分是信息展示,下半部分是一个RecyclerView列表,列表项里面的布局和相关操作下拉刷新上拉加载,我们都可以复用之前首页的博文展示,这里只不过是数据源的不同。

      由于我们在搜索页面点击Item项的时候传递了Blog对象,我们就可以根据作者名来获取关于博客作者的一些信息,这里是接口:http://wcf.open.cnblogs.com/blog/u/{BLOGAPP}/posts/{PAGEINDEX}/{PAGESIZE} {BLOGAPP}代表作者的账号,{PAGEINDEX}代表页码,{PAGESIZE}代表每页的数据条数。

      重复的东西这里就不再多说了,这里讲点新引入的东西,细心的朋友可能有发现当我们更新数据(上拉刷新,下拉加载)的时候,列表底部有个弹出提示框,这个就是安卓5.0用来取代Toast的SnackBar:

    1             //snackbar提醒
    2                     Snackbar snackbar = Snackbar.make(mToolbar,"当前更新"+mBlogs.size()+"条博客信息",Snackbar.LENGTH_LONG);
    3                     snackbar.show();

    用法很简单,类似于Toast,不过不一样的是,它是具有交互效果的,也就是说我们可以在Snackbar上添加点击事件,关于Snackbar的详细用法,有兴趣的朋友自己网上找找资料吧。

      然后再来说下关于这个FAB(Floating Action Button)的移动效果,这里我采用的是共享元素移动,由于我们的博文详情页和博主详情页都具有这个控件,所以我们在切换Activity的时候可以进行动画设置,这里makeSceneTransitionAnimation的第二个参数为共享View,第三个参数为标志参数要与xml里的transitionName保持一致。

    1     android:transitionName="fab"
    1  startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(AuthorActivity.this, mFloatingActionButton, "fab").toBundle());

    好了,今天先写到这里,改天继续更新,有什么建议或疑问,可以在文章评论给我留言。

    作者:李晨玮
    出处:http://www.cnblogs.com/lichenwei/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
    正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!旁边有“推荐”二字,你就顺手把它点了吧,相得准,我分文不收;相不准,你也好回来找我!

  • 相关阅读:
    Silverlight & Blend动画设计系列一:偏移动画(TranslateTransform)
    如何在DeepEarth中进行图形绘制(点、线、多边形以及自定义图片图层)
    Bing Maps进阶系列六:使用Silverlight剪切(Clip)特性实现Bing Maps的迷你小地图
    解决 ICTCLAS 2009 Windows_JNI_32 在 Web Project无法使用的方法
    XListControl 改变颜色 行高
    设置 java.library.path其实是在 Apache Tomcat 的任务栏 Icon中设置
    ICTCLAS 2009 JNI_32 遇到MyEclipse Web Project下无法运行
    10分钟开始使用ICTCLAS Java版
    boost regex_search 找出所有 匹配串
    Boost 1_37_0 的安装以及在VC6.0中的使用
  • 原文地址:https://www.cnblogs.com/lichenwei/p/4764434.html
Copyright © 2020-2023  润新知