1.设计需求
服务器json数据包含新闻类别,新闻类别可以水平滚动,每个类别下包含多条新闻,新闻图片可以自动翻转~
2.Json数据
{ "name":"news", "count":3, "categorylist":[ { "name":"娱乐", "count":5, "newslist":[ { "title":"赵本山捐款千万办希望小学", "imgurl":"ent01.jpg", "contenturl":"ent01.html" }, { "title":"刘晓庆隐婚1年 拒收老公1千万", "imgurl":"ent02.jpg", "contenturl":"ent02.html" }, { "title":"韩总统朴槿惠变双眼皮疑整容", "imgurl":"ent03.jpg", "contenturl":"ent03.html" }, { "title":"李冰冰任泉否认参与内幕交易", "imgurl":"ent04.jpg", "contenturl":"ent04.html" }, { "title":"明星年收入:吴奇隆吴莫愁过亿", "imgurl":"ent05.jpg", "contenturl":"ent05.html" } ] }, { "name":"体育", "count":6, "newslist":[ { "title":"首尔FC抵达广州拒绝任何采访", "imgurl":"sport01.jpg", "contenturl":"sport01.html" }, { "title":"乔治21+6步行者擒公牛5连胜", "imgurl":"sport02.jpg", "contenturl":"sport02.html" }, { "title":"专访伊涅斯塔:梅西被批因太强", "imgurl":"sport03.jpg", "contenturl":"sport03.html" }, { "title":"男女篮亚锦赛折戟仍称霸亚洲", "imgurl":"sport04.jpg", "contenturl":"sport04.html" }, { "title":"梅西2球破3场球荒超C罗神迹", "imgurl":"sport05.jpg", "contenturl":"sport05.html" }, { "title":"双少45分雷霆斩小牛获两连胜", "imgurl":"sport05.jpg", "contenturl":"sport05.html" } ] }, { "name":"财经", "count":5, "newslist":[ { "title":"李嘉诚撤资香港或因不满港府", "imgurl":"money01.jpg", "contenturl":"money01.html" }, { "title":"收评:沪指跌0.48%失守120日线", "imgurl":"money02.jpg", "contenturl":"money02.html" }, { "title":"北京:取经英国治霾 应涨油价", "imgurl":"money03.jpg", "contenturl":"money03.html" }, { "title":"韩正澄清为何无北京领导揭牌", "imgurl":"money04.jpg", "contenturl":"money04.html" }, { "title":"北京现代请孙杨代言或被处罚", "imgurl":"money05.jpg", "contenturl":"money05.html" } ] }, { "name":"体育", "count":6, "newslist":[ { "title":"首尔FC抵达广州拒绝任何采访", "imgurl":"sport01.jpg", "contenturl":"sport01.html" }, { "title":"乔治21+6步行者擒公牛5连胜", "imgurl":"sport02.jpg", "contenturl":"sport02.html" }, { "title":"专访伊涅斯塔:梅西被批因太强", "imgurl":"sport03.jpg", "contenturl":"sport03.html" }, { "title":"男女篮亚锦赛折戟仍称霸亚洲", "imgurl":"sport04.jpg", "contenturl":"sport04.html" }, { "title":"梅西2球破3场球荒超C罗神迹", "imgurl":"sport05.jpg", "contenturl":"sport05.html" }, { "title":"双少45分雷霆斩小牛获两连胜", "imgurl":"sport05.jpg", "contenturl":"sport05.html" } ] }, { "name":"财经", "count":5, "newslist":[ { "title":"李嘉诚撤资香港或因不满港府", "imgurl":"money01.jpg", "contenturl":"money01.html" }, { "title":"收评:沪指跌0.48%失守120日线", "imgurl":"money02.jpg", "contenturl":"money02.html" }, { "title":"北京:取经英国治霾 应涨油价", "imgurl":"money03.jpg", "contenturl":"money03.html" }, { "title":"韩正澄清为何无北京领导揭牌", "imgurl":"money04.jpg", "contenturl":"money04.html" }, { "title":"北京现代请孙杨代言或被处罚", "imgurl":"money05.jpg", "contenturl":"money05.html" } ] }, { "name":"体育", "count":6, "newslist":[ { "title":"首尔FC抵达广州拒绝任何采访", "imgurl":"sport01.jpg", "contenturl":"sport01.html" }, { "title":"乔治21+6步行者擒公牛5连胜", "imgurl":"sport02.jpg", "contenturl":"sport02.html" }, { "title":"专访伊涅斯塔:梅西被批因太强", "imgurl":"sport03.jpg", "contenturl":"sport03.html" }, { "title":"男女篮亚锦赛折戟仍称霸亚洲", "imgurl":"sport04.jpg", "contenturl":"sport04.html" }, { "title":"梅西2球破3场球荒超C罗神迹", "imgurl":"sport05.jpg", "contenturl":"sport05.html" }, { "title":"双少45分雷霆斩小牛获两连胜", "imgurl":"sport05.jpg", "contenturl":"sport05.html" } ] }, { "name":"财经", "count":5, "newslist":[ { "title":"李嘉诚撤资香港或因不满港府", "imgurl":"money01.jpg", "contenturl":"money01.html" }, { "title":"收评:沪指跌0.48%失守120日线", "imgurl":"money02.jpg", "contenturl":"money02.html" }, { "title":"北京:取经英国治霾 应涨油价", "imgurl":"money03.jpg", "contenturl":"money03.html" }, { "title":"韩正澄清为何无北京领导揭牌", "imgurl":"money04.jpg", "contenturl":"money04.html" }, { "title":"北京现代请孙杨代言或被处罚", "imgurl":"money05.jpg", "contenturl":"money05.html" } ] }, { "name":"体育", "count":6, "newslist":[ { "title":"首尔FC抵达广州拒绝任何采访", "imgurl":"sport01.jpg", "contenturl":"sport01.html" }, { "title":"乔治21+6步行者擒公牛5连胜", "imgurl":"sport02.jpg", "contenturl":"sport02.html" }, { "title":"专访伊涅斯塔:梅西被批因太强", "imgurl":"sport03.jpg", "contenturl":"sport03.html" }, { "title":"男女篮亚锦赛折戟仍称霸亚洲", "imgurl":"sport04.jpg", "contenturl":"sport04.html" }, { "title":"梅西2球破3场球荒超C罗神迹", "imgurl":"sport05.jpg", "contenturl":"sport05.html" }, { "title":"双少45分雷霆斩小牛获两连胜", "imgurl":"sport05.jpg", "contenturl":"sport05.html" } ] }, { "name":"财经", "count":5, "newslist":[ { "title":"李嘉诚撤资香港或因不满港府", "imgurl":"money01.jpg", "contenturl":"money01.html" }, { "title":"收评:沪指跌0.48%失守120日线", "imgurl":"money02.jpg", "contenturl":"money02.html" }, { "title":"北京:取经英国治霾 应涨油价", "imgurl":"money03.jpg", "contenturl":"money03.html" }, { "title":"韩正澄清为何无北京领导揭牌", "imgurl":"money04.jpg", "contenturl":"money04.html" }, { "title":"北京现代请孙杨代言或被处罚", "imgurl":"money05.jpg", "contenturl":"money05.html" } ] }, { "name":"体育", "count":6, "newslist":[ { "title":"首尔FC抵达广州拒绝任何采访", "imgurl":"sport01.jpg", "contenturl":"sport01.html" }, { "title":"乔治21+6步行者擒公牛5连胜", "imgurl":"sport02.jpg", "contenturl":"sport02.html" }, { "title":"专访伊涅斯塔:梅西被批因太强", "imgurl":"sport03.jpg", "contenturl":"sport03.html" }, { "title":"男女篮亚锦赛折戟仍称霸亚洲", "imgurl":"sport04.jpg", "contenturl":"sport04.html" }, { "title":"梅西2球破3场球荒超C罗神迹", "imgurl":"sport05.jpg", "contenturl":"sport05.html" }, { "title":"双少45分雷霆斩小牛获两连胜", "imgurl":"sport05.jpg", "contenturl":"sport05.html" } ] }, { "name":"财经", "count":5, "newslist":[ { "title":"李嘉诚撤资香港或因不满港府", "imgurl":"money01.jpg", "contenturl":"money01.html" }, { "title":"收评:沪指跌0.48%失守120日线", "imgurl":"money02.jpg", "contenturl":"money02.html" }, { "title":"北京:取经英国治霾 应涨油价", "imgurl":"money03.jpg", "contenturl":"money03.html" }, { "title":"韩正澄清为何无北京领导揭牌", "imgurl":"money04.jpg", "contenturl":"money04.html" }, { "title":"北京现代请孙杨代言或被处罚", "imgurl":"money05.jpg", "contenturl":"money05.html" } ] } ] }
3.代码实现
/** * * @author http://blog.csdn.net/zimo2013 * */ public class MainActivity extends FragmentActivity implements OnClickListener, OnPageChangeListener { private RadioGroup rgTitle; private TextView tvContent; private TextView tvTitle; private ScrollView svContent; private ViewPager viewPager; private ImageGuideAdapter adapter; private LinearLayout layoutBottom; private LinearLayout[] layouts; private NewsInfo newsInfo; private int currCategoryIndex; private String currContentUrl = ""; private Category currCategory; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 请求无标题栏 requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); init(); // 开启任务加载数据 new JsonTask(handler).start(); adapter = new ImageGuideAdapter(getSupportFragmentManager(), handler); viewPager.setAdapter(adapter); viewPager.setOnPageChangeListener(this); } // 初始化 private void init() { rgTitle = (RadioGroup) findViewById(R.id.rg_title); tvContent = (TextView) findViewById(R.id.tv_content); tvTitle = (TextView) findViewById(R.id.tv_title); viewPager = (ViewPager) findViewById(R.id.pager); svContent = (ScrollView) findViewById(R.id.sv_content); layoutBottom = (LinearLayout) findViewById(R.id.layoutl_bottom); // 得到屏幕的宽度 int width = getWindowManager().getDefaultDisplay().getWidth(); ViewGroup.LayoutParams params = viewPager.getLayoutParams(); params.width = width; params.height = width / 2; // 由于viewpager图片等比2:1,故设定viewpager的高度为宽度的1/2 viewPager.setLayoutParams(params); } private Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case Constant.STATUS_NET_ERROR: showMessage("网络异常!"); break; case Constant.STATUS_JSON_OK: String json = new String((byte[]) msg.obj); // 解析json Gson Gson = new Gson(); Type type = new TypeToken<NewsInfo>() { }.getType(); newsInfo = Gson.fromJson(json, type); // 初始化数据 initJson(); break; case Constant.STATUS_IMG_OK: ImageView iv = (ImageView) msg.obj; iv.setImageBitmap((Bitmap) iv.getTag()); break; case Constant.STATUS_CONTENT_OK: String result = new String((byte[]) msg.obj); if (msg.arg1 == currContentUrl.hashCode()) {// 没有错位 tvContent.setText(result); svContent.scrollTo(0, 0); } break; case Constant.STATUS_NEXT_PAGE: viewPager.setCurrentItem(msg.arg1, true); break; } } }; /** * 初始化数据,动态添加radioButton按钮 */ public void initJson() { List<Category> categories = newsInfo.getCategorylist(); ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(100, ViewGroup.LayoutParams.MATCH_PARENT); for (Category category : categories) { RadioButton button = new RadioButton(this); button.setText(category.getName()); button.setGravity(Gravity.CENTER); button.setButtonDrawable(R.drawable.boundary_line); button.setLayoutParams(params); button.setBackgroundResource(R.drawable.selector_title_btn); // button.setTextColor(getResources().getColor(R.color.selector_text)); button.setOnClickListener(this); rgTitle.addView(button); } currCategoryIndex = 0; //当前类别 currCategory = categories.get(currCategoryIndex); update(); } /** * 更新当前类别新闻的数据 * */ public void update() { layoutBottom.removeAllViews(); // 移除所有子view adapter.setList(currCategory.getNewslist()); adapter.notifyDataSetChanged(); int size = currCategory.getNewslist().size(); layouts = new LinearLayout[size]; //动态添加图片导航提示区域 LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); params.leftMargin = 5; for (int i = 0; i < size; i++) { layouts[i] = new LinearLayout(this); layouts[i].setLayoutParams(params); System.out.println("layoutBottom:" + layoutBottom); layoutBottom.addView(layouts[i]); } refreshGuide(0); } /** * 刷新向导进度 * * @param pos */ public void refreshGuide(int pos) { int size = currCategory.getNewslist().size(); for (int i = 0; i < size; i++) { if (i == pos) { layouts[i].setBackgroundResource(R.drawable.shape_guide_light); } else { layouts[i].setBackgroundResource(R.drawable.shape_guide_normal); } } //使用handler,动态延迟刷新下一页 Message msg = handler.obtainMessage(); msg.what = Constant.STATUS_NEXT_PAGE; if (pos >= size - 1) { msg.arg1 = 0; } else { msg.arg1 = pos + 1; } handler.sendMessageDelayed(msg, 5 * 1000); } /** * 输出吐司 * * @param str */ public void showMessage(String str) { Toast.makeText(this, str, 0).show(); } /** * 不同类别新闻button的click事件 */ @Override public void onClick(View v) { currContentUrl = "";// 当前内容url置空 tvContent.setText(""); // 详细新闻页置空 tvTitle.setText("新闻客户端"); viewPager.setCurrentItem(0); currCategoryIndex = rgTitle.indexOfChild(v); currCategory = newsInfo.getCategorylist().get(currCategoryIndex); update();// 更新当前类别的新闻数据 } @Override public void onPageSelected(int position) { News news = currCategory.getNewslist().get(position); String url = news.getContenturl(); if (currContentUrl.equals(url)) { System.out.println("不重复下载内容!"); return; } currContentUrl = url; tvTitle.setText(news.getTitle()); //开启任务,动态下载详细数据 new ContentTask(handler, currContentUrl).start(); handler.removeMessages(Constant.STATUS_NEXT_PAGE); //先移除消息,可能还存在延迟尚未处理的消息 refreshGuide(position); //重新刷新导航提示,和发送消息 } @Override public void onPageScrollStateChanged(int state) { } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } }
/** * * @author http://blog.csdn.net/zimo2013 * */ public class ImageGuideAdapter extends FragmentStatePagerAdapter { private Handler handler; private List<News> lists = new ArrayList<News>(); private List<ImageGuideFragment> fragments = new ArrayList<ImageGuideFragment>(); public void setList(List<News> lists) { this.lists = lists; if(fragments != null){ fragments.clear(); } for (int i = 0; i < lists.size(); i++) { fragments.add(new ImageGuideFragment()); } } public ImageGuideAdapter(FragmentManager fm, Handler handler) { super(fm); this.handler = handler; } @Override public Fragment getItem(int pos) { News news = lists.get(pos); ImageGuideFragment fragment = fragments.get(pos); Bundle bundle = new Bundle(); bundle.putString("title", news.getTitle()); bundle.putString("imgurl", news.getImgurl()); fragment.setArguments(bundle); //为fragment设置handler,如果缓存中不存在该图片,可以开启网络下载,当下载完成之后,利用handler可以再加载图片资源 fragment.setHandler(handler); return fragment; } @Override public int getCount() { return lists.size(); } }
/** * * @author http://blog.csdn.net/zimo2013 * */ public class ImageGuideFragment extends Fragment{ private Handler handler; private String title; private String imgurl; public void setHandler(Handler handler){ this.handler = handler; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle bundle = getArguments(); title = bundle.getString("title"); imgurl = bundle.getString("imgurl"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.item_image, null); ImageView ivImg = (ImageView) view.findViewById(R.id.item_iv_img); TextView tvTitle = (TextView) view.findViewById(R.id.item_tv_title); tvTitle.setText(title); if(!TextUtils.isEmpty(imgurl)){ //存在图片url链接 Bitmap bitmap = AppCacheManager.getManager().getCacheBitmapByKey(imgurl); if(bitmap != null){ //缓存中存在图片资源 System.out.println(imgurl+"图片发现!"); ivImg.setImageBitmap(bitmap); }else{ //开启多线程,下载图片 new ImageTask(handler, ivImg, imgurl).start(); } } return view; } }
<!-- activity_main.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/bg" android:gravity="center" android:text="新闻客户端" android:textColor="#ffffffff" android:textSize="22sp" /> <HorizontalScrollView android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#ffe7e7e7" android:scrollbarThumbHorizontal="@drawable/bar" > <RadioGroup android:id="@+id/rg_title" android:layout_width="wrap_content" android:layout_height="45dp" android:orientation="horizontal" > </RadioGroup> </HorizontalScrollView> <View android:layout_width="fill_parent" android:layout_height="2dp" android:background="@color/bg" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <android.support.v4.view.ViewPager android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="100dp" > </android.support.v4.view.ViewPager> <LinearLayout android:id="@+id/layoutl_bottom" android:layout_width="wrap_content" android:layout_height="20dp" android:layout_alignBottom="@+id/pager" android:layout_alignParentRight="true" android:layout_marginRight="10dp" android:gravity="center_vertical" android:orientation="horizontal" > </LinearLayout> </RelativeLayout> <View android:layout_width="fill_parent" android:layout_height="2dp" android:background="@color/bg" /> <ScrollView android:id="@+id/sv_content" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/list_bg" > <TextView android:id="@+id/tv_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" /> </ScrollView> </LinearLayout>
<!-- item_image.xml --> <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="2dp" android:orientation="vertical" > <ImageView android:id="@+id/item_iv_img" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitXY" android:src="@drawable/pic_no" /> <TextView android:id="@+id/item_tv_title" android:layout_width="match_parent" android:layout_height="20dp" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:background="#77181410" android:gravity="left" android:maxLines="1" android:paddingLeft="10dp" android:textColor="@android:color/white" android:textSize="15sp" /> </RelativeLayout>
这里只粘贴关键代码,实体类和三级缓存就没有粘贴在这里,有兴趣的朋友,可以关注我后期关于三级缓存的实现,此处我只是抛砖引玉,希望大家能够指正或者提出更好的实现,