仿今日头条和QQ侧滑和智慧北京的小项目3
本项目图片素材均来自今日头条,QQ侧滑没有使用Android原生的NavigationDrawer,而使用的是第三方SlidingMenu,原因是这个控件暂时没有仔细研究(后期会研究并写demo),项目整体可以说是使用了一个Activity加多个Fragment,全部采用沉寂式。
前文摘要:仿今日头条和QQ侧滑和智慧北京的小项目2
TabPager(NewsPager新闻页面对应的11个子页面)
此页面相对比较复杂,所以单独用一篇blog来说明都处理了哪些逻辑
从网络上获取json数据
private void getDataFromNet() {
HttpUtils httpUtils = new HttpUtils();
httpUtils.send(HttpRequest.HttpMethod.GET, url, new RequestCallBack<Object>() {
@Override
public void onSuccess(ResponseInfo<Object> responseInfo) {
if (isRefresh) {
isRefresh = false;
listNews.onRefreshFinish(true);
}
Log.d(TAG, newsMenuTab.getTitle() + "数据请求成功" + responseInfo.result);
//数据请求成功向本地保存一份
CacheUtils.putString(mActivity, url, String.valueOf(responseInfo.result));
//解析json
resolutionJson((String) responseInfo.result);
}
@Override
public void onFailure(HttpException e, String s) {
if (isRefresh) {
listNews.onRefreshFinish(false);
}
Log.d(TAG, newsMenuTab.getTitle() + "数据请求失败");
}
});
}
解析json数据
解析json数据分为若干部分,解析json、初始化数据、设置数据、处理和解析数据。
- 解析json(javaBean在此不做赘述,获取json,直接生成即可)
private TopNewsBean topNewsJson(String result) {
Gson gson = new Gson();
TopNewsBean topNewsBean;
topNewsBean = gson.fromJson(result, TopNewsBean.class);
return topNewsBean;
}
- 初始化数据、设置数据
/**
* 解析json数据
*
* @param result
*/
private void resolutionJson(String result) {
TopNewsBean topNewsBean = topNewsJson(result);
if (!isLoadMore){
//把解析json封装成一个方法这样看起来代码没那么乱
topNewsList = topNewsBean.getData().getTopnews();
moreUrl = topNewsBean.getData().getMore();
if (TextUtils.isEmpty(moreUrl)) {
moreUrl = null;
}else {
moreUrl = ConstantUtils.CONNECTURL+moreUrl;
}
//初始化顶部新闻的Viewpager数据
//初始化Viewpager数据
TopNewsTabAdapter topNewsTabAdapter = new TopNewsTabAdapter();
// 给ViewPager设置数据
hvp.setAdapter(topNewsTabAdapter);
hvp.setOnPageChangeListener(this);
//初始化文字和点
llPoint.removeAllViews();//因为访问网络读取缓存这个方法会被执行2此,所以需要要移除以前的view
View view = null;
for (int i = 0; i < topNewsList.size(); i++) {
view = new View(mActivity);
view.setBackgroundResource(R.drawable.point_seclect);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(15, 15);
if (i != 0) {
params.leftMargin = 15;
}
view.setEnabled(false);
view.setLayoutParams(params);
llPoint.addView(view);
}
//初始化第一个点和文字
firstDescription = 0;
tvTopNewsDes.setText(topNewsList.get(firstDescription).getTitle());
llPoint.getChildAt(firstDescription).setEnabled(true);
//初始化listview数据
newsItem = topNewsBean.getData().getNews();
listNewsAdapter = new ListNewsAdapter();
listNews.setAdapter(listNewsAdapter);
// TODO: 16/5/28 给Viewpager设置自动滑动
//因为该方法会执行2次,所以需要清空一次
if (myHandle==null){
myHandle = new MyHandle();
}else {
myHandle.removeCallbacksAndMessages(null);
}
myHandle.postDelayed(new MyRunnable(),4000);
}else {
isLoadMore = false;
List<TopNewsBean.DataBean.NewsBean> moreNewsItem = topNewsBean.getData().getNews();
newsItem.addAll(moreNewsItem);
listNewsAdapter.notifyDataSetChanged();
}
}
- 处理和解析数据
1、轮播图数据
class TopNewsTabAdapter extends PagerAdapter {
@Override
public int getCount() {
return topNewsList.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView imageView = new ImageView(mActivity);
//给imageview设置事件
//设置默认图片和背景拉伸
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setBackgroundResource(R.drawable.default_bg);
bitmapUtils = new BitmapUtils(mActivity);
// 配置默认图片的像素单位
bitmapUtils.configDefaultBitmapConfig(Bitmap.Config.ARGB_4444);
//topimage的网络地址
topNews = topNewsList.get(position);
/**
* container 下面的uri参数请求下来的图片, 设置给container来展示.
* uri 图片的请求地址
*/
bitmapUtils.display(imageView, topNews.getTopimage());
container.addView(imageView);
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
2、列表listview新闻数据
class ListNewsAdapter extends BaseAdapter {
@Override
public int getCount() {
return newsItem.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
convertView = View.inflate(mActivity, R.layout.listnews_item, null);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) convertView.getTag();
}
TopNewsBean.DataBean.NewsBean newsBean = newsItem.get(position);
viewHolder.tvListNews.setText(newsBean.getTitle());
viewHolder.tvListDate.setText(newsBean.getPubdate());
// 判断当前是否是已读的新闻
String readableIDArray = CacheUtils.getString(mActivity, READABLE_NEWS_ID_ARRAY_KEY, null);
// TODO: 16/5/27
if(!TextUtils.isEmpty(readableIDArray)
&& readableIDArray.contains(newsBean.getId()+"")) {
viewHolder.tvListNews.setTextColor(Color.GRAY);
} else {
viewHolder.tvListNews.setTextColor(Color.BLACK);
}
//设置默认图片
viewHolder.ivListNews.setBackgroundResource(R.drawable.listnews_default_bg);
bitmapUtils.display(viewHolder.ivListNews,newsBean.getListimage());
return convertView;
}
class ViewHolder {
@Bind(R.id.iv_list_news)
public ImageView ivListNews;
@Bind(R.id.tv_list_news)
public TextView tvListNews;
@Bind(R.id.tv_list_date)
public TextView tvListDate;
ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
}
viewpager轮播新闻页面逻辑
设置点和文字的自动切换、自动轮播
设置点和文字的自动切换
1、给Viewpager设置页面滑动监听
2、初始化点和文字描述控件
//初始化文字和点
llPoint.removeAllViews();//因为访问网络读取缓存这个方法会被执行2此,所以需要要移除以前的view
View view = null;
for (int i = 0; i < topNewsList.size(); i++) {
view = new View(mActivity);
view.setBackgroundResource(R.drawable.point_seclect);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(15, 15);
if (i != 0) {
params.leftMargin = 15;
}
view.setEnabled(false);
view.setLayoutParams(params);
llPoint.addView(view);
}
//初始化第一个点和文字
firstDescription = 0;
tvTopNewsDes.setText(topNewsList.get(firstDescription).getTitle());
llPoint.getChildAt(firstDescription).setEnabled(true);
3、主要实现onPageSelected方法
//Viewpager的滑动事件监听
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
//设置点的切换
tvTopNewsDes.setText(topNewsList.get(position).getTitle());
llPoint.getChildAt(firstDescription).setEnabled(false);
llPoint.getChildAt(position).setEnabled(true);
firstDescription = position;
}
@Override
public void onPageScrollStateChanged(int state) {
}
自动轮播(通过Handle实现,定时任务)
为什么执行2次,第一次从缓存中读取数据,并处理数据,第二次从网络上获取数据,并处理数据。
// TODO: 16/5/28 给Viewpager设置自动滑动
//因为该方法会执行2次,所以需要清空一次
if (myHandle==null){
myHandle = new MyHandle();
}else {
myHandle.removeCallbacksAndMessages(null);
}
myHandle.postDelayed(new MyRunnable(),4000);
}else {
isLoadMore = false;
List<TopNewsBean.DataBean.NewsBean> moreNewsItem = topNewsBean.getData().getNews();
newsItem.addAll(moreNewsItem);
listNewsAdapter.notifyDataSetChanged();
}
//Handle
class MyHandle extends Handler{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//用于处理消息
int newCurrentItem = (hvp.getCurrentItem() + 1)%topNewsList.size();
hvp.setCurrentItem(newCurrentItem);
//消息处理完在重新发送,类似递归
myHandle.postDelayed(new MyRunnable(),4000);
}
}
//run方法
class MyRunnable implements Runnable{
@Override
public void run() {
//发一条空的消息
myHandle.sendEmptyMessage(0);
}
}
列表新闻listview页面逻辑处理(自定义Listview)
下拉刷新、上拉加载
写一个类继承自listview,添加自定义头布局和尾布局,监听滑动事件等。
以下贴出关键代码。
下拉刷新部分
添加头布局
/**
* 添加头布局
*/
private void initHeadView() {
headView = View.inflate(getContext(), R.layout.refresh_headview, null);
ButterKnife.bind(this, headView);
this.addHeaderView(headView);
//默认隐藏头布局
headView.measure(0, 0);
measuredHeight = headView.getMeasuredHeight();
headView.setPadding(0, -measuredHeight, 0, 0);
initAnimation();
}
处理Listview的点击事件
/**
* 重新onTouchEvent,处理点击事件
* @param ev
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
if (downY == -1){
downY = (int) ev.getY();
}
// downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
if (downY == -1){
downY = (int) ev.getY();
}
int moveY = (int) ev.getY();
int diffY = moveY - downY;
// 判断当前是否正在刷新中
if(currentState == RELEASEREFRESH) {
// 当前正在刷新中, 不执行下拉, 直接跳出
break;
}
//如果是从上向下滑动,并且是第一个头布局,才进行下拉操作
boolean isDisplay = isDisplaySecondHeaderView();
if (diffY>0&&isDisplay) {
int piddingTop = -measuredHeight+diffY;
if (piddingTop >= 0 && currentState != RELEASEREFRESH){
Log.i(TAG, "进入释放刷新状态");
currentState = RELEASEREFRESH;
refreshState();
}else if (piddingTop<0 && currentState != DOWNREFRESH){
Log.i(TAG, "进入下拉刷新");
currentState = DOWNREFRESH;
refreshState();
}
headView.setPadding(0,piddingTop,0,0);
return true;
}
break;
case MotionEvent.ACTION_UP:
downY = -1;
if(currentState == DOWNREFRESH) {
// 当前是下拉刷新, 把头布局的隐藏
headView.setPadding(0, -measuredHeight, 0, 0);
} else if(currentState == RELEASEREFRESH) {
// 当前是释放刷新, 进入到正在刷新中的状态
currentState = INREFRESH;
refreshState();
headView.setPadding(0, 0, 0, 0);
// 调用用户的回调事件, 刷新数据
if(mOnRefreshListener != null) {
mOnRefreshListener.onPullDownRefresh();
}
}
break;
}
return super.onTouchEvent(ev);
//判断3种状态
private void refreshState() {
switch (currentState) {
case DOWNREFRESH: //下拉刷新
ivRefresh.startAnimation(downAnima);
tvRefresh.setText("下拉刷新");
break;
case RELEASEREFRESH: //释放刷新
ivRefresh.startAnimation(upAnima);
tvRefresh.setText("松开刷新");
break;
case INREFRESH: //刷新中
ivRefresh.clearAnimation();
ivRefresh.setVisibility(View.INVISIBLE);
pbBar.setVisibility(View.VISIBLE);
tvRefresh.setText("正在刷新中..");
break;
}
}
定义回调接口
public interface OnRefreshListener {
/**
* 当下拉刷新时触发此方法
*/
public void onPullDownRefresh();
public void onLoadingMore();
}
上拉加载更多部分
/**
* 添加角布局
*/
private void initFooterView() {
footView = View.inflate(getContext(), R.layout.listview_footerview, null);
footView.measure(0,0);
footViewHeight = footView.getMeasuredHeight();
this.addFooterView(footView);
footView.setPadding(0, -footViewHeight, 0, 0);
this.setOnScrollListener(new OnScrollListener() {
//当页面改变是调用
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// 当滚动停止时, 或者惯性滑动时, ListView最后一个显示的条目索引为getCount -1;
if(scrollState == SCROLL_STATE_IDLE ||
scrollState == SCROLL_STATE_FLING) {
if(getLastVisiblePosition() == getCount() -1 && !isLoadingMore) {
System.out.println("滚动到底部了");
isLoadingMore = true;
footView.setPadding(0, 0, 0, 0);
// 让ListView滚动到底部
setSelection(getCount());
// 调用使用者的回调事件
if(mOnRefreshListener != null) {
mOnRefreshListener.onLoadingMore();
}
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
});
}
NewsDetailUI类(Listview页面item条目的事件处理)
点击listview条目进入一个新的页面,通过WebView展示一个web网页
listNews.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
int newsposition = position - 2;
newsBeanItem = newsItem.get(newsposition);
// 先把已读新闻的id取出来
String readableIDArray = CacheUtils.getString(mActivity, READABLE_NEWS_ID_ARRAY_KEY, "");
if(!readableIDArray.contains(newsBeanItem.getId()+"")) {
String currentID = null;
if(TextUtils.isEmpty(readableIDArray)) {
currentID = newsBeanItem.getId() + ", ";
} else {
currentID = readableIDArray + newsBeanItem.getId() + ", ";
}
// 把这条新闻的id存储起来
CacheUtils.putString(mActivity, READABLE_NEWS_ID_ARRAY_KEY, currentID);
}
listNewsAdapter.notifyDataSetChanged();
Intent intent = new Intent(mActivity, NewsDetailUI.class);
intent.putExtra("url", newsBeanItem.getUrl());
intent.putExtra("title",newsBeanItem.getTitle());
mActivity.startActivity(intent);
}
});
初始化数据
private void initData() {
mIbFinish.setVisibility(View.VISIBLE);
mIbTextSize.setVisibility(View.VISIBLE);
mIbShare.setVisibility(View.VISIBLE);
mTvTitle.setMaxWidth(600);
mTvTitle.setMaxLines(1);
mTvTitle.setEllipsize(TextUtils.TruncateAt.valueOf("END"));
mTvTitle.setText(getIntent().getStringExtra("title"));
String url = getIntent().getStringExtra("url");
settings = mWebView.getSettings();
// settings.setJavaScriptEnabled(true); // 启用javascript脚本
// settings.setBuiltInZoomControls(true); // 启用界面上放大和缩小按钮
// settings.setUseWideViewPort(true); // 启用双击放大, 双击缩小功能
mWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
mPbLoading.setVisibility(View.GONE);
}
});
mWebView.loadUrl(url);
}
设置字体大小
/**
* 设置webView的字体大小
*/
private void setTextSize() {
AlertDialog.Builder ab = new AlertDialog.Builder(this);
ab.setTitle("选择字体大小");
String[] item = new String[]{"超大号字体","大号字体","正常字体","小号字体","超小号字体"};
ab.setSingleChoiceItems(item, currentSelectTextSize, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
tempCurrent = which;
}
});
ab.setNeutralButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
currentSelectTextSize = tempCurrent;
changeTextSize();
}
});
ab.setPositiveButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
ab.show();
}
share分享(第三方sdk使用在这里暂时不做介绍,根据官方文档一步一步就行了)
/**
* 一键社会化分享
*/
private void mobShare() {
ShareSDK.initSDK(this);
OnekeyShare oks = new OnekeyShare();
//关闭sso授权
oks.disableSSOWhenAuthorize();
// 分享时Notification的图标和文字 2.5.9以后的版本不调用此方法
//oks.setNotification(R.drawable.ic_launcher, getString(R.string.app_name));
// title标题,印象笔记、邮箱、信息、微信、人人网和QQ空间使用
oks.setTitle("智慧北京");
// titleUrl是标题的网络链接,仅在人人网和QQ空间使用
oks.setTitleUrl("http://sharesdk.cn");
// text是分享文本,所有平台都需要这个字段
oks.setText("我是分享文本");
// imagePath是图片的本地路径,Linked-In以外的平台都支持此参数
//oks.setImagePath("/sdcard/test.jpg");//确保SDcard下面存在此张图片
// url仅在微信(包括好友和朋友圈)中使用
oks.setUrl("http://sharesdk.cn");
// comment是我对这条分享的评论,仅在人人网和QQ空间使用
oks.setComment("我是测试评论文本");
// site是分享此内容的网站名称,仅在QQ空间使用
oks.setSite(getString(R.string.app_name));
// siteUrl是分享此内容的网站地址,仅在QQ空间使用
oks.setSiteUrl("http://sharesdk.cn");
// 启动分享GUI
oks.show(this);
}
PhotosPager(组图页面的实现)
简单几步,获取数据,解析数据
初始化数据
@Override
public void initData() {
bitmapUtils = new BitmapUtils(mActivity);
bitmapUtils.configDefaultBitmapConfig(Bitmap.Config.ARGB_4444);
url = ConstantUtils.PHOTOSURL;
//先从缓存中读取数据
String photosJsonData = CacheUtils.getString(mActivity, url, null);
if (photosJsonData != null) {
parserJsonData(photosJsonData);
}
//从网络上请求数据
getDataFromNet();
}
private void getDataFromNet() {
HttpUtils httpUtils = new HttpUtils();
httpUtils.send(HttpRequest.HttpMethod.GET, url, new RequestCallBack<Object>() {
@Override
public void onSuccess(ResponseInfo<Object> responseInfo) {
//请求成功本地存一份json,解析json
// Log.d(TAG, "onSuccess: "+responseInfo.result);
String result = (String) responseInfo.result;
parserJsonData(result);
CacheUtils.putString(mActivity, url, result);
}
@Override
public void onFailure(HttpException e, String s) {
Log.e(TAG, "onFailure: 组图数据请求失败。" + e);
}
});
}
解析数据
private void parserJsonData(String result) {
PhotosBean photosBean = parserJson(result);
//主要取得数据图片的url+title
photoNews = photosBean.getData().getNews();
//设置listview数据
PhotoAdapter photoAdapter = new PhotoAdapter();
llPhotos.setAdapter(photoAdapter);
}
private PhotosBean parserJson(String result) {
Gson gson = new Gson();
PhotosBean photosBean = gson.fromJson(result, PhotosBean.class);
return photosBean;
}
class PhotoAdapter extends BaseAdapter {
@Override
public int getCount() {
return photoNews.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = View.inflate(mActivity, R.layout.photos_list_item, null);
viewHolder.ivPhotoPhotos = (ImageView) convertView.findViewById(R.id.iv_photo_photos);
viewHolder.tvTitlePhotos = (TextView) convertView.findViewById(R.id.tv_title_photos);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) convertView.getTag();
}
PhotosBean.DataBean.NewsBean newsBean = photoNews.get(position);
viewHolder.tvTitlePhotos.setText(newsBean.getTitle());
//设置默认图片
viewHolder.ivPhotoPhotos.setImageResource(R.drawable.default_bg);
bitmapUtils.display(viewHolder.ivPhotoPhotos,newsBean.getListimage());
return convertView;
}
public class ViewHolder {
// @Bind(R.id.iv_photo_photos)
public ImageView ivPhotoPhotos;
// @Bind(R.id.tv_title_photos)
public TextView tvTitlePhotos;
}
}
切换视图
/**
* 用于切换视图的方法
* @param ib
*/
public void switchView(ImageButton ib) {
//more没有切换是listv
if (isSingleColumns) {
llPhotos.setVisibility(View.VISIBLE);
gvPhoto.setVisibility(View.GONE);
llPhotos.setAdapter(new PhotoAdapter());
isSingleColumns =false;
ib.setImageResource(R.mipmap.icon_pic_list_type);
}else {
llPhotos.setVisibility(View.GONE);
gvPhoto.setVisibility(View.VISIBLE);
gvPhoto.setAdapter(new PhotoAdapter());
isSingleColumns =true;
ib.setImageResource(R.mipmap.icon_pic_grid_type);
}
}
至此,本小项目完成。其他页面暂不做实现,其处理逻辑参考“新闻中心”页面即可。
关于作者
- 个人主页:Hsia
- Email:[email protected]
- 项目地址:https://github.com/swordman20/Zhbj
时间: 2024-10-17 13:54:48