by seaicelin
转载请注明出处:http://blog.csdn.net/amd123456789/article/details/52292623
主页面
主页面从上到下由DrawerLayout + ToolBar + SwipeRefreshLayout + RecylerView + HomeProtocol组成。
- DrawerLayout : 用于实现抽屉效果的侧边栏菜单。
- ToolBar : 用于实现标题栏,类似以前ActionBar。
- SwipeRefreshLayout:用于实现下拉刷新效果,直接包裹着RecylerView。
- RecylerView:主要用于显示日报的列表的ListView。
先来一睹主页面的效果(不会搞GIF图,并且手上是平板!),也就是这篇文章所要实现的效果图:
DrawerLayout 主页面和侧边栏抽屉效果
DrawerLayout是V4包提供的一个widget,需要在activity和布局文件里边操作来实现这个效果。布局界面包含侧边栏界面和主页面界面。布局文件按照规定的格式书写如下:
activity_content.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 内容显示 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar"></include>
//包裹下拉刷新
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/light_grey">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/light_grey">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
<!--侧边栏-->
<LinearLayout
android:id="@+id/drawer_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"//可以设置左边还是右边侧滑
android:background="@android:color/white"
android:orientation="vertical"></LinearLayout>
</android.support.v4.widget.DrawerLayout>
写好布局文件后,我们再来看看activity是怎么实现这个效果的, 请看下面代码:
...
private ActionBarDrawerToggle mDrawerToggle;
@InjectView(R.id.drawer)
DrawerLayout drawerLayout;
...
//设置侧边栏
private void setDrawerLayout() {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);//和Toolbar也绑定
mDrawerToggle.syncState();
drawerLayout.setDrawerListener(mDrawerToggle);
}
ToolBar
ToolBar是android5.0推出的一个新控件,用来替换ActionBar,说是更加灵活。如何使用?
首先,要设置这个activity的主题为不包含actionBar.
//no action bar
<style name="AppToolBarTheme" parent="Theme.AppCompat.Light.NoActionBar">
</style>
//Toolbar布局文件如下,Toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar 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="wrap_content"
android:background="@android:color/holo_blue_light"
app:popupTheme="@style/ThemeOverlay.AppCompat.ActionBar"
app:theme="@style/AppBaseTheme">
</android.support.v7.widget.Toolbar>
接着,在Activity里面加入Toolbar相关代码。
@InjectView(R.id.toolbar)
Toolbar toolbar;
//设置ToolBar
private void setToolBar() {
toolbar.setTitle(R.string.home_page);
toolbar.setNavigationIcon(R.mipmap.ic_drawer_am);
setSupportActionBar(toolbar);//设置Toolbar
}
//设置ToolBar的相关选项
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.toolbar_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem menu) {
switch (menu.getItemId()) {
case R.id.action_login:
break;
case R.id.action_night:
break;
case R.id.action_settiong:
break;
default:
break;
}
return true;
}
ToolBar里面的选项,是加载res/menu/toolbar_menu.xml这个布局文件:
<?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"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".ContentActivity">
<item
android:id="@+id/action_login"
android:icon="@mipmap/ic_drawer_am"
android:orderInCategory="100"
android:title="Login"
app:showAsAction="always" />
<item
android:id="@+id/action_settiong"
android:orderInCategory="100"
android:title="action_settings"
app:showAsAction="never" />
<item
android:id="@+id/action_night"
android:orderInCategory="100"
android:title="Night"
app:showAsAction="never"></item>
</menu>
SwipeRefreshLayout下拉刷新
下拉刷新只需要在布局文件的最外层包裹他就可以了,布局文件请看前面activity_content.xml的布局文件。在ContentActivity去实现SwipeRefreshLayout.OnRefreshListener。请看代码:
//设置下拉刷新
private void setSwipeLayout() {
swipeRefreshLayout.setOnRefreshListener(this);
swipeRefreshLayout.setColorSchemeResources(R.color.blue);
}
//下拉刷新监听
@Override
public void onRefresh() {
BaseApplication.getHandler().postDelayed(new Runnable() {
@Override
public void run() {
swipeRefreshLayout.setRefreshing(false);//刷新完毕
Toast.makeText(BaseApplication.getApplication(), "刷新成功", Toast.LENGTH_SHORT).show();
}
}, 3000);
}
RecylerView列表控件
RecylerView也是V7包下的控件,我们简单理解为ListView控件的升级版就行。它的使用,无非就是
1. 设置布局管理器。
2. 设置适配器。
3. 设置Item相关ItemAnimator,增删动画。
在ContentActivity里面数据加载后,设置RecylerView。
//初始化数据相关
private void initData() {
homeProtocol = new HomeProtocol();
new Thread(new Runnable() {
@Override
public void run() {
homeInfo = homeProtocol.loadData();
BaseApplication.getHandler().postDelayed(new Runnable() {
@Override
public void run() {
setRecylerView();
}
}, 500);
}
}).start();
}
//设置recyler view
private void setRecylerView() {
HomeRecylerViewAdapter adapter = new HomeRecylerViewAdapter(homeInfo);//适配器
LinearLayoutManager layoutManager = new LinearLayoutManager(BaseApplication.getApplication());//布局信息,设置Item显示的样式
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recylerView.setLayoutManager(layoutManager);//设置LayoutManager
recylerView.setAdapter(adapter);//设置适配器
}
HomeRecylerViewAdapter主要就三个方法
1. getItemCount
2. onCreateViewHolder
3. onBindViewHolder
package com.example.seaice.zhihuribao.adapter;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.seaice.zhihuribao.R;
import com.example.seaice.zhihuribao.Utils.BaseApplication;
import com.example.seaice.zhihuribao.bean.HomeInfo;
import com.example.seaice.zhihuribao.bean.HomeStoriesInfo;
import com.example.seaice.zhihuribao.bean.HomeTopInfo;
import com.example.seaice.zhihuribao.view.CircleIndicator;
import com.squareup.picasso.Picasso;
import java.util.List;
import butterknife.ButterKnife;
/**
* Created by seaice on 2016/8/22.
*/
public class HomeRecylerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private static final int TYPE_DATE = 2;
private LayoutInflater mInflate;
private Context mContext;
private List<HomeStoriesInfo> homeStoriesInfos;
private List<HomeTopInfo> homeTopInfos;
private HomeInfo homeInfo;
private boolean isTouchViewPager = false;
private boolean isViewPagerLoop = false;
public HomeRecylerViewAdapter(HomeInfo homeInfo) {
this.homeInfo = homeInfo;
initData();
}
private void initData() {
homeStoriesInfos = homeInfo.getHomeStoriesInfos();
homeTopInfos = homeInfo.getHomeTopInfoList();
mContext = BaseApplication.getApplication();
mInflate = LayoutInflater.from(mContext);
}
//绑定不同类型Holder
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER) {
View view = mInflate.inflate(R.layout.header_recyler_view, parent, false);
return new HeaderHolder(view);
} else if (viewType == TYPE_DATE) {
View view = mInflate.inflate(R.layout.date_recyler_view, parent, false);
return new DateHolder(view);
} else if (viewType == TYPE_ITEM) {
View view = mInflate.inflate(R.layout.item_recyler_view, parent, false);
return new MyViewHolder(view);
}
throw new RuntimeException("there is no type that match the type " + viewType);
}
//设置holder的view元素
@Override
public void onBindViewHolder(RecyclerView.ViewHolder vh, int position) {
if (vh instanceof HeaderHolder) {
if(isViewPagerLoop == false){
isViewPagerLoop = true;
setViewPager((HeaderHolder) vh);
}
} else if (vh instanceof DateHolder) {
} else if (vh instanceof MyViewHolder) {
HomeStoriesInfo info = homeStoriesInfos.get(position - 2);
MyViewHolder holder = (MyViewHolder) vh;
holder.tv_title.setText(info.getTitle());
Picasso.with(BaseApplication.getApplication()).load(info.getImages()).into(holder.iv_title);
} else {
throw new RuntimeException("there is no holer that match the " + vh);
}
}
@Override
public int getItemCount() {
return homeStoriesInfos.size() + 1;
}
@Override
public int getItemViewType(int position) {
if (isPositionHeader(position)) {
return TYPE_HEADER;
} else if (isPositionDate(position)) {
return TYPE_DATE;
} else {
return TYPE_ITEM;
}
}
private boolean isPositionDate(int position) {
return position == 1;
}
private boolean isPositionHeader(int position) {
return position == 0;
}
//设置viewPager
private void setViewPager(final HeaderHolder holder) {
holder.viewPager.setAdapter(new HomeViewPagerAdapter(homeTopInfos));
holder.indicator.setCircleNumber(homeTopInfos.size());
holder.viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
holder.indicator.setSelectdItem(position);
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_DRAGGING) {
isTouchViewPager = true;
} else {
isTouchViewPager = false;
}
}
});
loopViewPager(holder);
}
//让viewpager循环播放
private void loopViewPager(final HeaderHolder holder) {
BaseApplication.getHandler().postDelayed(new Runnable() {
@Override
public void run() {
if (isTouchViewPager == false) {
int item = (holder.viewPager.getCurrentItem()) + 1;
holder.viewPager.setCurrentItem(item % (holder.viewPager.getAdapter().getCount()));
holder.indicator.setSelectdItem(item);
}
loopViewPager(holder);
}
}, 5000);
}
//item view
public class MyViewHolder extends RecyclerView.ViewHolder {
public ImageView iv_title;
public TextView tv_title;
public MyViewHolder(View view) {
super(view);
iv_title = ButterKnife.findById(view, R.id.iv_title);
tv_title = ButterKnife.findById(view, R.id.tv_title);
}
}
//header view
public class HeaderHolder extends RecyclerView.ViewHolder {
public ViewPager viewPager;
public CircleIndicator indicator;
public HeaderHolder(View view) {
super(view);
viewPager = ButterKnife.findById(view, R.id.viewPager);
indicator = ButterKnife.findById(view, R.id.indicator);
}
}
//dateHolder view
public class DateHolder extends RecyclerView.ViewHolder {
public TextView tv_date;
public DateHolder(View view) {
super(view);
tv_date = ButterKnife.findById(view, R.id.tv_date);
}
}
}
HomeProtocol加载数据
HomeProtocol的逻辑实际上和GuideProtocol逻辑是一样的,那么此刻可以提取出一个基类,然后子类去实现各自的方法便可以。
基类,提取为BaseProtocol,后面子类只需要各自实现三个抽象方法便可以。
1. paserJsonData(String json) …//解析json数据
2. getCacheDir()….//获取缓存的文件路劲
3. getUrl()…//获取网页地址
package com.example.seaice.zhihuribao.protocol;
import android.util.Log;
import com.example.seaice.zhihuribao.Utils.FileUtils;
import com.example.seaice.zhihuribao.Utils.HttpUtils;
import com.example.seaice.zhihuribao.Utils.LogUtils;
import com.example.seaice.zhihuribao.bean.GuideInfo;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import okhttp3.Request;
import okhttp3.Response;
/**
* Created by seaice on 2016/8/18.
*/
public abstract class BaseProtocol<T> {
//解析json数据
protected abstract T paserJsonData(String json);
//获取连接路径
protected abstract String getCacheDir();
//获取新闻链接网址
protected abstract String getUrl();
/**
* 1.先从本地获取json数据
* 2.如果为空,再从服务器上获取
* 3.若获取到json,保存到本地
* 4.获取到json不为空,解析json数据
*/
public T loadData() {
String json = loadDataFromLocal();
if (json == null) {
LogUtils.e("从服务器获取json");
json = loadDataFromServer();
if (json != null) {
saveDataToLocal(json);
}
} else {
LogUtils.e("已经从本地获取");
}
if (json != null) {
return paserJsonData(json);
}
return null;
}
//1.把整个json文件写到一个本地文件中
//2.把每条数据摘出来保存到数据库中
private String loadDataFromLocal() {
File dir = FileUtils.getCacheDir();
File file = new File(dir, getCacheDir());
try {
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
long saveTime = Long.parseLong(br.readLine());
if (System.currentTimeMillis() > saveTime) {
return null;
} else {
String str;
StringWriter sw = new StringWriter();
while ((str = br.readLine()) != null) {
sw.write(str);
}
LogUtils.i("本地获取数据");
return sw.toString();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
//把数据保存到本地
private void saveDataToLocal(String json) {
LogUtils.i("保存到本地");
//第一行写时间,然后保存起来
File dir = FileUtils.getCacheDir();
File file = new File(dir, getCacheDir());
BufferedWriter bw = null;
try {
FileWriter fw = new FileWriter(file);
bw = new BufferedWriter(fw);
bw.write(System.currentTimeMillis() + 1000 * 100 + "");
bw.newLine();
bw.write(json);
bw.flush();
fw.close();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//从服务器加载数据
private String loadDataFromServer() {
String result = null;
Request request = new Request.Builder().url(getUrl()).build();
Response response = null;
response = HttpUtils.execute(request);
if (response != null && response.isSuccessful()) {
try {
result = response.body().string();
LogUtils.e(result);
return result;
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
好了,那么剩下的就交给子类HomeProtocol.java来实现
package com.example.seaice.zhihuribao.protocol;
import com.example.seaice.zhihuribao.Utils.LogUtils;
import com.example.seaice.zhihuribao.bean.HomeInfo;
import com.example.seaice.zhihuribao.bean.HomeStoriesInfo;
import com.example.seaice.zhihuribao.bean.HomeTopInfo;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
/**
* Created by seaice on 2016/8/18.
*/
public class HomeProtocol extends BaseProtocol<HomeInfo> {
private static final String HOMEURL = "http://news-at.zhihu.com/api/4/news/latest";
private static final String HOMECACHE = "home";
@Override
protected HomeInfo paserJsonData(String json) {
try {
JSONObject jsonObject = new JSONObject(json);
String date = jsonObject.getString("date");
JSONArray jsonArrayStories = jsonObject.getJSONArray("stories");
List<HomeStoriesInfo> homeStoriesInfos = new ArrayList<HomeStoriesInfo>();
for (int i = 0; i < jsonArrayStories.length(); i++) {
JSONObject object = jsonArrayStories.getJSONObject(i);
int type = object.getInt("type");
String id = object.getString("id");
String ga_prefix = object.getString("ga_prefix");
String title = object.getString("title");
String images = object.getString("images");
String image = images.substring(2, images.length()-2);
image = image.replace("\\", "");//去掉这个斜杠才能得到数据,take me a lot of time
HomeStoriesInfo homeStoriesInfo = new HomeStoriesInfo(image, type,id,ga_prefix,title);
LogUtils.e(homeStoriesInfo.toString());
homeStoriesInfos.add(homeStoriesInfo);
}
JSONArray jsonArrayTop = jsonObject.getJSONArray("top_stories");
List<HomeTopInfo> homeTopInfoList = new ArrayList<HomeTopInfo>();
for (int i = 0; i < jsonArrayTop.length(); i++) {
JSONObject object = jsonArrayTop.getJSONObject(i);
String image = object.getString("image");
int type = object.getInt("type");
String id = object.getString("id");
String ga_prefix = object.getString("ga_prefix");
String title = object.getString("title");
HomeTopInfo homeTopInfo = new HomeTopInfo(image,type,id,ga_prefix,title);
homeTopInfoList.add(homeTopInfo);
}
HomeInfo homeInfo = new HomeInfo(date, homeStoriesInfos,homeTopInfoList);
return homeInfo;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
@Override
protected String getCacheDir() {
return HOMECACHE;
}
@Override
protected String getUrl() {
return HOMEURL;
}
}
ViewPager主页面第一条Item
RecylerView的第一条Item是一个ViewPager,不是其他普通的目录。怎么区分对待这种不同的Item呢?我的做法就是用不同的viewHolder,设置不同的type,让adapter区分处理。详细见上面的HomeRecylerViewAdapter。其他Item用CardView来实现,布局文件item_revyler_view.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:contentPadding="5dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="5dp"
app:cardElevation="1dp"
app:cardPreventCornerOverlap="true"
app:cardUseCompatPadding="true"
android:layout_marginBottom="2dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_title"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_alignParentRight="true"
android:layout_margin="5dp" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_margin="5dp"
android:layout_toLeftOf="@id/iv_title"
android:gravity="center_vertical"
android:textColor="@android:color/black"
android:textSize="18sp"
android:ellipsize="end"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
再来说说viewPager,他是V4包里一个被用到烂的控件,实现左右滑动的效果。下面的圆点作为indicator指示滑动到哪个界面,自定义一个layout来画底部的圆点。
看看viewpager的布局文件, header_recyler_view.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl_vp"
android:layout_width="match_parent"
android:layout_height="200dp">
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="200dp"></android.support.v4.view.ViewPager>
<com.example.seaice.zhihuribao.view.CircleIndicator
android:id="@+id/indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/viewPager"
android:layout_centerHorizontal="true"
android:layout_marginBottom="8dp" />
</RelativeLayout>
其中CircleIndicator是底部的圆点,自定义view:
package com.example.seaice.zhihuribao.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import com.example.seaice.zhihuribao.R;
public class CircleIndicator extends View {
private int mCount;//设置格数
private int selectItem;//当前选中
private float mRadius;//原点半径
private float mSelectRadius;//选中原点半径
private float mSpace;//圆形间隔
private Paint mPaint;//画笔
public CircleIndicator(Context context) {
this(context, null);
}
public CircleIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
setSize();
}
//设置圆点的大小
private void setSize() {
DisplayMetrics metrcs = getResources().getDisplayMetrics();
mRadius = 2 * metrcs.density;
mSelectRadius = 3 * metrcs.density;
mSpace = 12 * metrcs.density;
}
//初始化画笔
private void initPaint() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(getResources().getColor(R.color.light_grey));
mPaint.setStyle(Paint.Style.FILL);
}
public void setViewPager(ViewPager pager) {
mCount = pager.getAdapter().getCount();
invalidate();
}
//设置圆点的个数
public void setCircleNumber(int num){
mCount = num;
invalidate();
}
//设置选中的圆点
public void setSelectdItem(int position) {
selectItem = position;
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
private int measureWidth(int widthMeasureSpec) {
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
int result;
if (specMode != MeasureSpec.EXACTLY) {
result = (int) (getPaddingLeft() + getPaddingRight() + mSpace * mCount);
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(specSize, result);
}
} else {
result = specSize;
}
return result;
}
private int measureHeight(int heightMeasureSpec) {
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
int result;
if (specMode != MeasureSpec.EXACTLY) {
result = (int) (getPaddingTop() + getPaddingBottom() + mSelectRadius * 2);
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(specSize, result);
}
} else {
result = specSize;
}
return result;
}
//画圆点
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float y = getHeight() / 2f;
float x = mSpace / 2f;
for (int i = 0; i < mCount; i++) {
if (i != selectItem) {
canvas.drawCircle(x, y, mRadius, mPaint);
} else {
canvas.drawCircle(x, y, mSelectRadius, mPaint);
}
x += mSpace;
}
}
}
至此,主页面的效果基本是做出来了,基本上用到的控件也都说清楚了。那么接下来的问题是:
- RecylerView 如何上拉加载更多条目?
这个问题,留到下一篇解决,现在我也不知道怎么弄,嘿嘿。
代码我都上传到GitHub了,公司上传不了,只能每次拷贝回家上传代码。地址是:
https://github.com/jwsn/zhihuribao2
欢迎查阅!!