题目要求:
完成下列效果,页面上方横向滑动栏,下方通过ViewPager加载Fragment实现效果,标题栏动态添加TextView,当点击的时候下方的ViewPager跳转到相应页面,使用HttpUrlConnection处理网络请求,列表图片使用universal-image-loader加载,自定义BaseApplication,项目的Application集成BaseApplication,并在Application中初始化universal-image-loader,配置图片的色彩模式为RGB565,用PullToRefresh实现上拉加载更多,下拉刷新的功能。接口如下:
http://gank.io/api/data/数据类型/请求个数/第几页
参数说明如下:
数据类型:福利、Android、iOS、休息视频、拓展资源、前端、all
请求个数:数字,大于0
第几页:数字,大于0
例如:http://gank.io/api/data/Android/10/1
功能代码:
一. MainActivity.java
package com.example; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.view.ViewPager; import android.os.Bundle; import android.view.Window; import android.widget.RadioGroup; import com.adapter.MyFragmentPagerAdapter; import com.fragment.Mine_Fragment; import com.fragment.ShouYe_Fragment; import com.fragment.Wei_Fragment; import com.fragment.XiGua_Fragment; import java.util.ArrayList; import java.util.List; public class MainActivity extends FragmentActivity { private ViewPager main_viewPager; private RadioGroup group; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); group = (RadioGroup) findViewById(R.id.groups); main_viewPager = (ViewPager) findViewById(R.id.main_viewPager); //定义集合添加显示的页面数据 List<Fragment> data = new ArrayList<>(); data.add(new ShouYe_Fragment()); data.add(new XiGua_Fragment()); data.add(new Wei_Fragment()); data.add(new Mine_Fragment()); main_viewPager.setOffscreenPageLimit(data.size()); //设置适配器 MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), data); main_viewPager.setAdapter(adapter); //设置viewpager的监听事件 main_viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { group.check(group.getChildAt(position).getId()); } @Override public void onPageScrollStateChanged(int state) { } }); //RadioGroup的监听事件 group.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup radioGroup, int i) { switch (i){ case R.id.button_01: main_viewPager.setCurrentItem(0,false); break; case R.id.button_02: main_viewPager.setCurrentItem(1,false); break; case R.id.button_03: main_viewPager.setCurrentItem(2,false); break; case R.id.button_04: main_viewPager.setCurrentItem(3,false); break; default: break; } } }); } }
二.自定义的适配器:
1. MyAdapter.java(适应于显示的条目布局)
package com.adapter; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.bean.NewsBean; import com.example.R; import com.nostra13.universalimageloader.core.ImageLoader; import com.util.ImageLoaderUtil; import java.util.List; public class MyAdapter extends BaseAdapter{ private List<NewsBean.ResultsBean> list; private Context context; public MyAdapter(Context context, List<NewsBean.ResultsBean> list) { this.context = context; this.list = list; } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null){ convertView =View.inflate(context, R.layout.item_layout,null); holder =new ViewHolder(); //查找控件 holder.image = (ImageView) convertView.findViewById(R.id.image); holder.title = (TextView) convertView.findViewById(R.id.title); convertView.setTag(holder); }else { holder = (ViewHolder) convertView.getTag(); } //获取数据重新赋值 holder.title.setText(list.get(position).getDesc()); if (list.get(position).getImages() != null){ ImageLoader.getInstance().displayImage(list.get(position).getImages().get(0),holder.image, ImageLoaderUtil.getDefaultOption()); } return convertView; } static class ViewHolder{ TextView title; ImageView image; } }
2. MyFragmentPagerAdapter.java(适用于显示的Fragment布局)
package com.adapter; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import java.util.List; public class MyFragmentPagerAdapter extends FragmentPagerAdapter{ private List<Fragment> data; public MyFragmentPagerAdapter(FragmentManager fm, List<Fragment> data) { super(fm); this.data = data; } @Override public Fragment getItem(int position) { return data.get(position); } @Override public int getCount() { return data.size(); } }
三.自定义bean类实现类
四.自定义的Fragment实现类:
1. 显示首页的 ShouYe_Fragment.java
package com.fragment; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.example.R; import java.util.ArrayList; import java.util.List; public class ShouYe_Fragment extends Fragment{ private TabLayout tabLayout; private ViewPager viewPager; private List<String> list; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { //设置布局 View view = inflater.inflate(R.layout.shouye_layout, container, false); tabLayout = (TabLayout)view.findViewById(R.id.tabLayout); viewPager = (ViewPager) view.findViewById(R.id.viewPager); return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); list = new ArrayList<>(); list.add("福利"); list.add("Android"); list.add("iOS"); list.add("休息视频"); list.add("拓展资源"); list.add("all"); list.add("福利"); list.add("Android"); viewPager.setOffscreenPageLimit(list.size()); //设置使用ViewPager+Fragment显示新闻列表数据布局的适配器 viewPager.setAdapter(new FragmentPagerAdapter(getChildFragmentManager()) { //得到当前页的标题,,,也就是设置当前页面显示的标题是tabLayout对应的标题 @Override public CharSequence getPageTitle(int position) { return list.get(position); } @Override public Fragment getItem(int position) { //在这个位置对比一下标题是什么,,,然后返回对应的fragment ShouYe_Child_Fragment shouYe_child_fragment = new ShouYe_Child_Fragment(); //判断所选的标题,进行传值显示 Bundle bundle = new Bundle();bundle.putString("name",list.get(position));shouYe_child_fragment.setArguments(bundle);
return shouYe_child_fragment;
}
@Override
public int getCount() {
return list.size();
}
});
//TabLyout要与ViewPager关联显示
tabLayout.setupWithViewPager(viewPager);
}}
2. 为首页数据传值的ShouYe_Child_Fragment.java
package com.fragment; import com.example.R; import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import com.adapter.MyAdapter; import com.google.gson.Gson; import com.handmark.pulltorefresh.library.ILoadingLayout; import com.handmark.pulltorefresh.library.PullToRefreshBase; import com.handmark.pulltorefresh.library.PullToRefreshListView; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import com.bean.NewsBean; import com.util.StringUtil; public class ShouYe_Child_Fragment extends Fragment{ //记录当前页面所有的数据....上拉或下拉添加到集合 private List<NewsBean.ResultsBean> list = new ArrayList<>(); private PullToRefreshListView refreshListView; private int page_num = 1; //下拉刷新的页数 private ILoadingLayout startLabels; private ILoadingLayout endLabels; private MyAdapter adapter; private String data; private String encode; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.shouye_child_layout, container, false); refreshListView = (PullToRefreshListView) view.findViewById(R.id.refresh_list_view); return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); //获取传递的标题数据,把获取的标题转码实现 Bundle bundle = getArguments(); String data = bundle.getString("name", "福利"); encode = URLEncoder.encode(data); //异步加载网络数据的方法 getDataFromNet(); //1.设置刷新的模式(PullToRefreshBase.Mode.BOTH:上下都可以刷新加载) refreshListView.setMode(PullToRefreshBase.Mode.BOTH); //2.设置刷新显示的文字 startLabels = refreshListView.getLoadingLayoutProxy(true, false); startLabels.setPullLabel("下拉刷新"); startLabels.setRefreshingLabel("正在刷新..."); startLabels.setReleaseLabel("放开刷新"); endLabels = refreshListView.getLoadingLayoutProxy(false, true); endLabels.setPullLabel("上拉刷新"); endLabels.setRefreshingLabel("正在载入..."); endLabels.setReleaseLabel("放开刷新..."); //3.设置监听事件 refreshListView.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener2<ListView>() { //下拉刷新 @Override public void onPullDownToRefresh(PullToRefreshBase<ListView> refreshView) { //当下拉刷新的时候,将第几页设成1,重新获取数据 getRefreshData(); } //当上拉加载更多的时候,将第几页的数字加1,重新获取; @Override public void onPullUpToRefresh(PullToRefreshBase<ListView> refreshView) { page_num++; getRefreshData(); } }); } /** * 下拉刷新获取数据 * 1.page_num 改变 * 2.每次添加到集合的前边 */ private void getRefreshData() { //1.创建异步任务的对象..第一个参数url路径Void,第二个参数表示进度Void,第三个参数返回值类型String(可以为空) AsyncTask<Void,Void,String> task = new AsyncTask<Void, Void, String>() { @Override protected String doInBackground(Void... params) { try { String path = "http://gank.io/api/data/"+encode+"/10/1"; //连接网络 URL url = new URL(path); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(5000); connection.setReadTimeout(5000); //响应数据 int responseCode = connection.getResponseCode(); if (responseCode == 200){ InputStream inputStream = connection.getInputStream(); String json = StringUtil.streamToString(inputStream,"utf-8"); return json; } } catch (Exception e) { e.printStackTrace(); } return ""; } @Override protected void onPostExecute(String result) { //解析数据 NewsBean newsBean = new Gson().fromJson(result, NewsBean.class); //把解析的数据添加到集合前面,设置适配器 list.addAll(0,newsBean.getResults()); setAdapter(); //停止刷新 refreshListView.onRefreshComplete(); //设置本次刷新的时间 Date date = new Date(System.currentTimeMillis()); SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm"); startLabels.setLastUpdatedLabel("上次刷新的时间为:"+dateFormat.format(date)); } }; task.execute(); } //获取网络数据 public void getDataFromNet() { //1.创建异步任务的对象..第一个参数url路径Void,第二个参数表示进度Void,第三个参数返回值类型String(可以为空) AsyncTask<Void,Void,String> task = new AsyncTask<Void, Void, String>() { @Override protected String doInBackground(Void... params) { try { String path = "http://gank.io/api/data/"+encode+"/10/"+page_num; //连接网络 URL url = new URL(path); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(5000); connection.setReadTimeout(5000); //响应数据 int responseCode = connection.getResponseCode(); if (responseCode == 200){ InputStream inputStream = connection.getInputStream(); String json = StringUtil.streamToString(inputStream,"utf-8"); return json; } } catch (Exception e) { e.printStackTrace(); } return ""; } @Override protected void onPostExecute(String result) { //解析数据 NewsBean newsBean = new Gson().fromJson(result, NewsBean.class); //把解析的数据添加到集合中,设置适配器 list.addAll(newsBean.getResults()); setAdapter(); //停止刷新 refreshListView.onRefreshComplete(); } }; task.execute(); } //设置适配器的方法 public void setAdapter(){ if (adapter == null){ adapter = new MyAdapter(getActivity(), list); refreshListView.setAdapter(adapter); }else { adapter.notifyDataSetChanged(); } } }
3. 其它fragment自定义
五. 自定义的工具类:
1. 全局初始化配置imageloader的BaseApplication.java
package com.util; import android.app.Application; //全局初始化Application类 public class BaseApplication extends Application { @Override public void onCreate() { super.onCreate(); //配置imageLoader ImageLoaderUtil.init(this); } }
2. ImageLoader配置各种格式的工具类:ImageLoaderUtil.java
package com.util; import android.content.Context; import android.graphics.Bitmap; import com.example.R; import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache; import com.nostra13.universalimageloader.cache.disc.naming.HashCodeFileNameGenerator; import com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import com.nostra13.universalimageloader.core.assist.ImageScaleType; import com.nostra13.universalimageloader.core.assist.QueueProcessingType; import com.nostra13.universalimageloader.core.decode.BaseImageDecoder; import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer; import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer; import com.nostra13.universalimageloader.core.download.BaseImageDownloader; import com.nostra13.universalimageloader.utils.StorageUtils; import java.io.File; public class ImageLoaderUtil { /** * 初始化imageLoader * @param context */ public static void init(Context context) { //1.获取配置config对象 File cacheDir = StorageUtils.getCacheDirectory(context); //缓存文件夹路径 ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context) .threadPoolSize(3) // default 线程池内加载的数量 .threadPriority(Thread.NORM_PRIORITY - 2) // default 设置当前线程的优先级 .tasksProcessingOrder(QueueProcessingType.FIFO) // default .denyCacheImageMultipleSizesInMemory() .memoryCache(new LruMemoryCache(2 * 1024 * 1024)) //可以通过自己的内存缓存实现 .memoryCacheSize(2 * 1024 * 1024) // 内存缓存的最大值 .memoryCacheSizePercentage(13) // default .diskCache(new UnlimitedDiscCache(cacheDir)) // default 可以自定义缓存路径 .diskCacheSize(50 * 1024 * 1024) // 50 Mb sd卡(本地)缓存的最大值 .diskCacheFileCount(100) // 可以缓存的文件数量 // default为使用HASHCODE对UIL进行加密命名, 还可以用MD5(new Md5FileNameGenerator())加密 .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) .imageDownloader(new BaseImageDownloader(context)) // default .imageDecoder(new BaseImageDecoder(true)) // default .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default .writeDebugLogs() // 打印debug log .build(); //开始构建 //2.初始化配置...ImageLoader.getInstance()图片加载器的对象,单例模式 ImageLoader.getInstance().init(config); } /** * imageLoader加载图片的默认选项 * @return */ public static DisplayImageOptions getDefaultOption(){ DisplayImageOptions options = new DisplayImageOptions.Builder() .showImageOnLoading(R.drawable.micro_pic) // 设置图片下载期间显示的默认图片 .showImageForEmptyUri(R.drawable.micro_pic) // 设置图片Uri为空或是错误的时候显示的图片 .showImageOnFail(R.drawable.micro_pic) // 设置图片加载或解码过程中发生错误显示的图片 .resetViewBeforeLoading(true) // default 设置图片在加载前是否重置、复位 .delayBeforeLoading(1000) // 下载前的延迟时间 .cacheInMemory(true) // default 设置下载的图片是否缓存在内存中 .cacheOnDisk(true) // default 设置下载的图片是否缓存在SD卡中 .considerExifParams(true) // default .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default 设置图片以如何的编码方式显示 .bitmapConfig(Bitmap.Config.RGB_565) // default 设置图片的解码类型 .displayer(new SimpleBitmapDisplayer()) // default 还可以设置圆角图片new RoundedBitmapDisplayer(20) .build(); return options; } /** * imageLoader加载圆角图片....指定圆角的大小 * @return */ public static DisplayImageOptions getRoundedOption(int corner){ DisplayImageOptions options = new DisplayImageOptions.Builder() .showImageOnLoading(R.drawable.micro_pic) // 设置图片下载期间显示的图片 .showImageForEmptyUri(R.drawable.micro_pic) // 设置图片Uri为空或是错误的时候显示的图片 .showImageOnFail(R.drawable.micro_pic) // 设置图片加载或解码过程中发生错误显示的图片 .resetViewBeforeLoading(true) // default 设置图片在加载前是否重置、复位 .delayBeforeLoading(1000) // 下载前的延迟时间 .cacheInMemory(true) // default 设置下载的图片是否缓存在内存中 .cacheOnDisk(true) // default 设置下载的图片是否缓存在SD卡中 .considerExifParams(true) // default .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default 设置图片以如何的编码方式显示 .bitmapConfig(Bitmap.Config.RGB_565) // default 设置图片的解码类型 .displayer(new RoundedBitmapDisplayer(corner)) // default 还可以设置圆角图片new RoundedBitmapDisplayer(20) .build(); return options; } }
3. 解析json数据的 StringUtil.java
package com.util; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; public class StringUtil { //解析数据的方法 public static String streamToString(InputStream inputStream, String charset) { try { InputStreamReader inputStreamReader = new InputStreamReader(inputStream,charset); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String s = null; StringBuilder builder = new StringBuilder(); while ((s = bufferedReader.readLine()) != null){ builder.append(s); } bufferedReader.close(); return builder.toString(); } catch (Exception e) { e.printStackTrace(); } return null; } }
六. 自定义的布局文件:
1. color文件夹下的 color.xml 设置 字体的颜色
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_checked="true" android:color="@color/selected"></item> <item android:state_checked="false" android:color="@color/defaulted"></item> </selector>
2. layout文件夹下的布局文件:
(1)主页面:activity_main.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.support.v4.view.ViewPager android:id="@+id/main_viewPager" android:layout_width="match_parent" android:layout_above="@+id/groups" android:layout_height="match_parent"></android.support.v4.view.ViewPager> <RadioGroup android:id="@+id/groups" android:orientation="horizontal" android:gravity="center_horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true"> <RadioButton android:text="首页" android:checked="true" android:layout_weight="1" style="@style/ButtonStyle" android:layout_width="0dp" android:id="@+id/button_01" android:textColor="@color/color" android:layout_height="wrap_content" /> <RadioButton android:text="西瓜视频" android:layout_weight="1" style="@style/ButtonStyle" android:layout_width="0dp" android:id="@+id/button_02" android:textColor="@color/color" android:layout_height="wrap_content" /> <RadioButton android:text="微头条" android:layout_weight="1" style="@style/ButtonStyle" android:layout_width="0dp" android:id="@+id/button_03" android:textColor="@color/color" android:layout_height="wrap_content" /> <RadioButton android:text="我的" android:layout_weight="1" style="@style/ButtonStyle" android:layout_width="0dp" android:id="@+id/button_04" android:textColor="@color/color" android:layout_height="wrap_content" /> </RadioGroup> </RelativeLayout>
(2)首页:shouye_layout.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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"> <RelativeLayout android:layout_height="50dp" android:background="#FF0000" android:layout_width="match_parent" > <TextView android:text="今日头条" android:textSize="21sp" android:id="@+id/jiinri" android:textStyle="bold" android:textColor="#ffffff" android:layout_marginLeft="10dp" android:layout_centerVertical="true" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <EditText android:layout_toRightOf="@+id/jiinri" android:layout_width="match_parent" android:layout_centerVertical="true" android:layout_marginRight="10dp" android:hint="请输入您所感兴趣的事" android:layout_marginLeft="18dp" android:layout_height="36dp" android:background="#ffffff" android:textColor="#c6c6b9" android:padding="6dp" /> </RelativeLayout> <android.support.design.widget.TabLayout android:layout_width="match_parent" app:tabSelectedTextColor="#FF0000" app:tabIndicatorHeight="0dp" android:id="@+id/tabLayout" android:layout_height="60dp" app:tabTextColor="#000000" app:tabMode="scrollable"> </android.support.design.widget.TabLayout> <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent"></android.support.v4.view.ViewPager> </LinearLayout>
(3)为首页传值:shouye_child_layout.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"> <com.handmark.pulltorefresh.library.PullToRefreshListView xmlns:ptr="http://schemas.android.com/apk/res-auto" android:layout_height="match_parent" android:layout_width="match_parent" android:id="@+id/refresh_list_view" ptr:ptrDrawable="@drawable/default_ptr_flip" ptr:ptrAnimationStyle="flip" ptr:ptrHeaderBackground="#383838" ptr:ptrHeaderTextColor="#FFFFFF" > </com.handmark.pulltorefresh.library.PullToRefreshListView> </RelativeLayout>
(4)展示条目:item_layout.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/image" android:layout_width="120dp" android:layout_height="120dp" android:src="@drawable/jinchen" android:layout_marginLeft="10dp" android:layout_gravity="center_vertical" /> <TextView android:textSize="18sp" android:id="@+id/title" android:textStyle="bold" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" /> </LinearLayout>
3. values文件夹下的布局文件:
(1)colors.xml中设置颜色
<!--字体颜色--> <color name="selected">#FF0000</color> <color name="defaulted">#000000</color>
(2)styles.xml中设置按钮的样式:
<style name="ButtonStyle"> <item name="android:button">@null</item> <item name="android:padding">10dp</item> <item name="android:gravity">center</item> </style>