个人博客客户端——My CSDN 的实现(3)
2016-06-05 14:43
246 查看
在这一篇博客开始就要开始介绍客户端的具体开发了
工程打开后的具体目录如下所示
各位看官在建立自己的工程时,需要将“ViewPagerIndicator”和“MaterialRefreshLayout”两个依赖库导入项目中,此外还要从GitHub加载Fresco。
加载Fresco的方法很简单,在build.gradle文件中加入以下语句即可
而实际上,工程中需要用到的所有依赖项都写在了“dependencies”中。
My CSDN的主界面是可以滑动切换的,这就用到了support.v4包下的ViewPager控件,在上边有着多个指示标签,用到了“viewpagerindicator”依赖库下的“TabPageIndicator”控件。
并用到了侧边栏“DrawerLayout ”控件。
主界面布局文如下:
而要使用ViewPager控件,需要为其指定适配器,因此需要自定义类继承FragmentPagerAdapter。
需要注意,在getItem()方法中,我们需要返回一个“TabFragment”对象,TabFragment即可以切换显示的页面。还要向该对象传入一个整形参数“position”,如果我们直接为TabFragmnet设定一个如下所示的带参数的构造函数
这似乎也可以起到传递带参数的作用,不过Android Studio会建议你采用Bundle来传递参数,因为该构造函数可能会破坏Fragment的生命周期。
因此,在MianActivity.java文件中,主要任务就是初始化各个组件,并设定各适配器,首次打开自动加载数据被解析等。
使用Fresco必须先初始化,这里使用的是默认设置。
当中,
在导航栏顶部和侧边栏顶部,共有两个头像,在打开App时,LoadImageAsync的作用就是用来联网加载头像的。当然,该头像只会联网加载一次,以后再次打开app时,会直接从本地缓存中加载图片,并能将图片设为圆形,这都是Fresco的强大功能。只有当博主对象改变了时,才会重新从网上加载图片。
滑动标签完成了,接下来就要为Fragment填充内容了,即显示博客列表。在这里我不打算使用ListView,用的是RecyclerView。此外,还要使用能够支持RecyclerView下拉刷新的MaterialRefreshLayout
博客列表的布局如下,可以看到就是在MaterialRefreshLayout当中包裹一个RecyclerView而已
看上图可以知道,RecyclerView的每一项包含了三个部分,即标题,简介,博客信息,使用的即是三个TextView。因此,还需要为子项设定布局
然后,再为RecyclerView指定一个适配器
当中,
在
需要重点说的是自定义的接口
在
在
这一篇博客先讲到这里,下一篇再来介绍博客内容该如何呈现~
工程打开后的具体目录如下所示
各位看官在建立自己的工程时,需要将“ViewPagerIndicator”和“MaterialRefreshLayout”两个依赖库导入项目中,此外还要从GitHub加载Fresco。
加载Fresco的方法很简单,在build.gradle文件中加入以下语句即可
compile 'com.facebook.fresco:fresco:0.10.0'
而实际上,工程中需要用到的所有依赖项都写在了“dependencies”中。
My CSDN的主界面是可以滑动切换的,这就用到了support.v4包下的ViewPager控件,在上边有着多个指示标签,用到了“viewpagerindicator”依赖库下的“TabPageIndicator”控件。
并用到了侧边栏“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:fitsSystemWindows="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffff" android:orientation="vertical"> <include layout="@layout/top" /> <com.viewpagerindicator.TabPageIndicator android:id="@+id/id_indicator" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#ed130f" /> <android.support.v4.view.ViewPager android:id="@+id/id_viewpager" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#eceff2" /> </LinearLayout> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_header" app:itemTextColor="#000" app:menu="@menu/activity_main_drawer" /> </android.support.v4.widget.DrawerLayout>
而要使用ViewPager控件,需要为其指定适配器,因此需要自定义类继承FragmentPagerAdapter。
/** * 页面适配器 * Created by ZY on 2016/5/25. */ public class PagerAdapter extends FragmentPagerAdapter { /** * 标签 */ public static String[] TAGS = new String[]{ "最新", Constant.DIRECTORY_1, Constant.DIRECTORY_2, Constant.DIRECTORY_3, Constant.DIRECTORY_4, Constant.DIRECTORY_5, Constant.DIRECTORY_6 }; public PagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { TabFragment tabFragment = new TabFragment(); Bundle bundle = new Bundle(); bundle.putInt("position", position); tabFragment.setArguments(bundle); return tabFragment; } @Override public int getCount() { return TAGS.length; } @Override public CharSequence getPageTitle(int position) { return TAGS[position]; } }
需要注意,在getItem()方法中,我们需要返回一个“TabFragment”对象,TabFragment即可以切换显示的页面。还要向该对象传入一个整形参数“position”,如果我们直接为TabFragmnet设定一个如下所示的带参数的构造函数
public TabFragment(int position){ this.position=position; }
这似乎也可以起到传递带参数的作用,不过Android Studio会建议你采用Bundle来传递参数,因为该构造函数可能会破坏Fragment的生命周期。
因此,在MianActivity.java文件中,主要任务就是初始化各个组件,并设定各适配器,首次打开自动加载数据被解析等。
使用Fresco必须先初始化,这里使用的是默认设置。
public class MainActivity extends FragmentActivity implements NavigationView.OnNavigationItemSelectedListener { private DrawerLayout mDrawerLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //使用Fresco前必需先初始化 Fresco.initialize(this); setContentView(R.layout.activity_main); Constant.init(MainActivity.this); initView(); } private void initView() { mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); SimpleDraweeView top_image = (SimpleDraweeView) findViewById(R.id.top_image); ViewPager mViewPager = (ViewPager) findViewById(R.id.id_viewpager); TabPageIndicator mTabPageIndicator = (TabPageIndicator) findViewById(R.id.id_indicator); NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); PagerAdapter mPageAdapter = new PagerAdapter(getSupportFragmentManager()); mViewPager.setAdapter(mPageAdapter); //将两个空间联系起来,并设定默认显示第一页 mTabPageIndicator.setViewPager(mViewPager, 0); top_image.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mDrawerLayout.openDrawer(GravityCompat.START); } }); navigationView.setNavigationItemSelectedListener(this); new LoadImageAsync().execute(); }
当中,
new LoadImageAsync().execute();语句是用来加载头像用的
在导航栏顶部和侧边栏顶部,共有两个头像,在打开App时,LoadImageAsync的作用就是用来联网加载头像的。当然,该头像只会联网加载一次,以后再次打开app时,会直接从本地缓存中加载图片,并能将图片设为圆形,这都是Fresco的强大功能。只有当博主对象改变了时,才会重新从网上加载图片。
/** * 用来加载主界面顶部头像以及侧边栏顶部头像 * 当前设置为仅主界面顶部显示博主头像 * 侧边栏为本地默认头像 * 如果去掉注释代码,则可以均显示为博主头像 */ class LoadImageAsync extends AsyncTask<Void, Void, String> { @Override protected String doInBackground(Void... params) { BlogAuthor blogAuthor = JsoupUtil.getBlogAutoMessage(); String avatarUrl = ""; if (blogAuthor != null) { avatarUrl = blogAuthor.getAvatarUrl(); } return avatarUrl; } @Override protected void onPostExecute(String avatarUrl) { Uri uri = Uri.parse(avatarUrl); SimpleDraweeView top_image = (SimpleDraweeView) findViewById(R.id.top_image); // SimpleDraweeView nav_head_image = (SimpleDraweeView) findViewById(R.id.nav_head_image); top_image.setImageURI(uri); // nav_head_image.setImageURI(uri); } }
滑动标签完成了,接下来就要为Fragment填充内容了,即显示博客列表。在这里我不打算使用ListView,用的是RecyclerView。此外,还要使用能够支持RecyclerView下拉刷新的MaterialRefreshLayout
博客列表的布局如下,可以看到就是在MaterialRefreshLayout当中包裹一个RecyclerView而已
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.cjj.MaterialRefreshLayout android:id="@+id/refresh" android:layout_width="match_parent" android:layout_height="match_parent" app:isLoadMore="true" app:overlay="true" app:progress_colors="@array/material_colors" app:progress_size_type="normal" app:wave_color="#60dcd7d7" app:wave_height_type="normal" app:wave_show="true"> <android.support.v7.widget.RecyclerView android:id="@+id/another_content_list" android:layout_width="match_parent" android:layout_height="match_parent" /> </com.cjj.MaterialRefreshLayout> </FrameLayout>
看上图可以知道,RecyclerView的每一项包含了三个部分,即标题,简介,博客信息,使用的即是三个TextView。因此,还需要为子项设定布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="150dp" android:orientation="vertical" android:padding="6dp"> <TextView android:id="@+id/blog_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="end" android:maxLines="1" android:textColor="@android:color/black" android:textSize="20sp" android:textStyle="bold" /> <TextView android:id="@+id/blog_introduction" android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="end" android:maxLines="4" android:textColor="@android:color/black" android:textSize="16sp" /> <TextView android:id="@+id/blog_msg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:layout_marginRight="6dp" android:textColor="@android:color/black" android:textSize="13sp" /> </LinearLayout>
然后,再为RecyclerView指定一个适配器
BlogItemListAdapter,让其继承自
RecyclerView.Adapter<BlogItemHolder>,
BlogItemHolder也是继承自
RecyclerView.ViewHolder的。
public class BlogItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public TextView blog_title; public TextView blog_introduction; public TextView blog_msg; public ItemOnClickListener itemOnClickListener; public BlogItemHolder(View itemView) { super(itemView); blog_title = (TextView) itemView.findViewById(R.id.blog_title); blog_introduction = (TextView) itemView.findViewById(R.id.blog_introduction); blog_msg = (TextView) itemView.findViewById(R.id.blog_msg); itemView.setOnClickListener(this); } public void setItemOnClickListener(ItemOnClickListener itemOnClickListener) { this.itemOnClickListener = itemOnClickListener; } @Override public void onClick(View v) { if (itemOnClickListener != null) { itemOnClickListener.OnItemClickListener(getAdapterPosition()); } } }
当中,
ItemOnClickListener是一个自定义的接口,因为RecvclerView没有提供子项点击监听方法,所以需要自己建立一个回调函数,用于在用户点击子项时跳转到具体博客内容页面。
在
BlogItemListAdapter中需要实现的方法有以下三个,具体实现看我提供的工程代码
//注意该方法的第二个参数viewType,在后边设定博客内适配器时会有很大用处 onCreateViewHolder(ViewGroup parent, int viewType) onBindViewHolder(BlogItemHolder holder, int position) getItemCount()
需要重点说的是自定义的接口
ItemOnClickListener,当中仅有一个
OnItemClickListener方法,并需要一个参数position,即点击的子项在列表中的行数。
/** * Created by ZY on 2016/5/29. * 自定义博客列表点击事件监听接口 */ public interface ItemOnClickListener { void OnItemClickListener(int position); }
在
BlogItemListAdapter中声明该接口并实现其方法,
Constant.USE_WEB用于判断是否启用WebView打开博客,这里无需理会。可以看到,用户点击后会跳转到新的Activity,用于呈现博客内容,传递的参数url是博客链接。
public ItemOnClickListener itemOnClickListener = new ItemOnClickListener() { @Override public void OnItemClickListener(int position) { String url = blogIntroductionList.get(position).getUrl(); Intent intent; if (!Constant.USE_WEB) { intent = new Intent(context, ContentByJsoupActivity.class); } else { intent = new Intent(context, ContentByWebActivity.class); } intent.putExtra("url", url); context.startActivity(intent); } };
在
onBindViewHolder(BlogItemHolder holder, int position)方法中再将
itemOnClickListener对象传递过去,这样就利用回调方法实现了对RecyclerCiew子项的点击事件的监听了。
holder.setItemOnClickListener(itemOnClickListener);
这一篇博客先讲到这里,下一篇再来介绍博客内容该如何呈现~
相关文章推荐
- HTML5笔记:跨域通讯、多线程、本地存储和多图片上传技术(转)
- 线程通信
- cocos2dx 历史版本下载问题
- java数学函数
- 剑指Offer----面试题23:从上往下打印二叉树(层序遍历)
- linux下ftp和ftps以及ftp基于mysql虚拟用户认证服务器的搭建
- 检测PC端和移动端的方法总结(转)
- JAVA_OA(五)(番外篇):SpringMVC乱码解决(post,get)
- 北京数联,呵呵
- ubuntu - sublime text3 中文输入(ibus)
- 操作系统---常见进程调度算法
- create table用圆括号()
- 学生常见问题(二)
- (某云平台+VPLC神器)助我解postfix邮件系统的疑问处理
- java变量&常量
- 项目签名
- 函数对象(3)
- python面向对象进阶 反射 单例模式
- HttpServletResponse对象(二)
- PHP面试总结