学习Android应用开发已经有一段时间了,对涉及应用开发的主要基础知识已经有了一定的了解,但是基本上写的代码都是一些单一知识点的演示Demo,与一个完整的产品相差甚远。要具备开发复杂的产品级应用的能力,在掌握了应用开发的基础知识的前提下,最好的方法莫过于模仿别人开发的优秀应用。在模仿中循序渐进,以程序员角度去看待每一个APP是如何实现的,它有什么优缺点,并从中提升自己。模范别人应用其实就是一种开发的学习手段,因为如果自己去开发,没有UI没有交互流程,那样的话,可能会比较难下手,当有了别人的交互流程和一些资源,你就可以去自己考虑如果实现相关功能,如何达到类似效果。可能你的方法没那么完善,实现效果没原版的那么绚丽,可是这些都带有你的思想,这就足够了。
今日头条新闻客户端是我平时使用比较多的一个Android应用,以它作为模仿目标是一个不错的选择,今天我们实现的效果图就是今日头条的标题栏 。
效果图:
首先我们先要实现导航栏功能 用TabLayout ViewPager Fragment实现以下效果:
敲代码前先导入jar包:
compile 'com.android.support:design:26.0.0-alpha1' //TabLayout compile 'com.android.support:support-v4:26.0.0-alpha1' //ViewPager compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' //图片缓存 compile 'org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2'//HttpClient网络请求 compile 'com.google.code.gson:gson:2.8.1' //Gson
设置权限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
代码:
首先在主页面布局:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.bawei.com.myapplication.MainActivity"> <android.support.design.widget.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="50dp" app:tabSelectedTextColor="@color/colorPrimary" app:tabTextColor="@android:color/tertiary_text_light" app:tabIndicatorColor="@color/colorPrimary" app:tabMode="scrollable" app:tabBackground="@color/colorAccent" app:tabTextAppearance="@android:style/TextAppearance.Holo.Large" app:tabIndicatorHeight="3dp" app:tabGravity="center" ></android.support.design.widget.TabLayout> <android.support.v4.view.ViewPager android:id="@+id/vp" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/tab_layout" > </android.support.v4.view.ViewPager> </RelativeLayout>
main:
package com.bawei.com.myapplication; import android.os.Bundle; 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.support.v7.app.AppCompatActivity; import java.util.ArrayList; import frangment.NewsFragment; public class MainActivity extends AppCompatActivity{ private ViewPager vp; private TabLayout tabLayout; private ArrayList<String> list; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tabLayout = (TabLayout) findViewById(R.id.tab_layout); vp = (ViewPager) findViewById(R.id.vp); list = new ArrayList<>(); list.add("头条"); list.add("社会"); list.add("国内"); list.add("国际"); list.add("娱乐"); list.add("体育"); list.add("军事"); list.add("科技"); list.add("财经"); list.add("时尚"); vp.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) { //得到当前页的标题,,,也就是设置当前页面显示的标题是tab对应的标题 @Override public CharSequence getPageTitle(int position) { return list.get(position); } @Override public Fragment getItem(int position) { //一般我们在这个位置对比一下标题是什么,,,然后返回对应的fragment //初始化fragment 对应position有多少,fragment有多少 NewsFragment newsFragment = new NewsFragment(); //初始化bundle (数据盒子,装数据元素) Bundle bundle = new Bundle(); //Fragment fragment = null; if (list.get(position).equals("头条")){ //fragment = new TouTiaoFragment(); bundle.putString("name","top"); }else if (list.get(position).equals("社会")){ bundle.putString("name","shehui"); }else if (list.get(position).equals("国内")){ bundle.putString("name","guonei"); }else if (list.get(position).equals("国际")){ bundle.putString("name","guoji"); }else if (list.get(position).equals("娱乐")){ bundle.putString("name","yule"); }else if (list.get(position).equals("体育")){ bundle.putString("name","tiyu"); }else if (list.get(position).equals("军事")){ bundle.putString("name","junshi"); }else if (list.get(position).equals("科技")){ bundle.putString("name","keji"); }else if (list.get(position).equals("财经")){ bundle.putString("name","caijing"); }else if (list.get(position).equals("时尚")){ bundle.putString("name","shishang"); } //给fragment 加bundle 数据 //activity与fragment 1.getset,2.接口回调,3.setArguments ,getAraguments newsFragment.setArguments(bundle); return newsFragment; } @Override public int getCount() { return list.size(); } }); tabLayout.setupWithViewPager(vp); } }Frangment:
package frangment; 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.bawei.com.myapplication.R; import util.MaTask; /** * Created by Wangrx on 2017/9/13. */ public class NewsFragment extends Fragment{ private ListView frangment_lv; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.frangment_item,null); frangment_lv = view.findViewById(R.id.frangment_lv); return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Bundle bundle = getArguments(); String string = bundle.getString("name", ""); String path = "http://v.juhe.cn/toutiao/index?type="+string+"&key=597b4f9dcb50e051fd725a9ec54d6653"; MaTask myTask = new MaTask(getActivity(),frangment_lv); myTask.execute(path); } }AsyncTask:
package util; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import com.bawei.com.myapplication.WebActivity; import com.google.gson.Gson; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.List; /** * Created by Wangrx on 2017/9/13. */ public class MaTask extends AsyncTask<String, Integer, String> { private Context context; private ListView lv; private List<JavaBean.ResultBean.DataBean> data; public MaTask(Context context, ListView lv) { this.context = context; this.lv = lv; } @Override protected String doInBackground(String... strings) { try { URL url = new URL(strings[0]); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setReadTimeout(5000); connection.setConnectTimeout(5000); int responseCode = connection.getResponseCode(); if (responseCode == 200){ InputStream inputStream = connection.getInputStream(); String s = setToString(inputStream, "utf-8"); return s; } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // HttpClient httpClient = new DefaultHttpClient(); // HttpGet httpGet = new HttpGet(strings[0]); // try { // HttpResponse httpResponse = httpClient.execute(httpGet); // if (httpResponse.getStatusLine().getStatusCode() == 200) { // HttpEntity entity = httpResponse.getEntity(); // String s = EntityUtils.toString(entity, "utf-8"); // return s; // } // } catch (IOException e) { // e.printStackTrace(); // } return null; } @Override protected void onPostExecute(String s) { super.onPostExecute(s); Gson gson = new Gson(); JavaBean bean = gson.fromJson(s, JavaBean.class); data = bean.getResult().getData(); MyAdapter myAdapter = new MyAdapter(context, data); lv.setAdapter(myAdapter); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { String url = data.get(i).getUrl(); Intent intent = new Intent(context, WebActivity.class); intent.putExtra("url",url); context.startActivity(intent); } }); } public String setToString(InputStream inputStream,String charset){ InputStreamReader inputStreamReader = null; try { inputStreamReader = new InputStreamReader(inputStream,charset); BufferedReader reader = new BufferedReader(inputStreamReader); String s; StringBuilder builder = new StringBuilder(); while ((s=reader.readLine())!=null){ builder.append(s); } reader.close(); return builder.toString(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } }设置适配器:
package util; 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.bawei.com.myapplication.R; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer; import java.util.List; /** * Created by Wangrx on 2017/9/12. */ public class MyAdapter extends BaseAdapter{ private Context context; private List<JavaBean.ResultBean.DataBean> data; public MyAdapter(Context context, List<JavaBean.ResultBean.DataBean> data) { this.context = context; this.data = data; } @Override public int getCount() { return data.size(); } @Override public Object getItem(int i) { return data.get(i); } @Override public long getItemId(int i) { return i; } @Override public View getView(int i, View view, ViewGroup viewGroup) { ViewHolder holder = null; if (view == null){ view = View.inflate(context,R.layout.item,null); holder = new ViewHolder(); holder.item_img = view.findViewById(R.id.item_img); holder.item_time = view.findViewById(R.id.item_time); holder.item_title = view.findViewById(R.id.item_title); view.setTag(holder); }else { holder = (ViewHolder) view.getTag(); } holder.item_time.setText(data.get(i).getDate()); holder.item_title.setText(data.get(i).getTitle()); DisplayImageOptions options = new DisplayImageOptions.Builder() .showImageOnLoading(R.mipmap.ic_launcher) //加载图片时的图片 .showImageForEmptyUri(R.mipmap.ic_launcher) //没有图片资源时的默认图片 .showImageOnFail(R.mipmap.ic_launcher) //加载失败时的图片 .cacheInMemory(true) //启用内存缓存 .cacheOnDisk(true) //启用外存缓存 .considerExifParams(true) //启用EXIF和JPEG图像格式 .displayer(new RoundedBitmapDisplayer(20)) //设置显示风格这里是圆角矩形 .build(); ImageLoader.getInstance().displayImage(data.get(i).getThumbnail_pic_s().toString(), holder.item_img, options); return view; } class ViewHolder{ ImageView item_img; TextView item_time; TextView item_title; } }图片缓存:
package util; import android.app.Application; import android.content.Context; import android.content.res.Configuration; import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache; import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import com.nostra13.universalimageloader.core.assist.QueueProcessingType; import java.io.File; /** * Created by Wangrx on 2017/9/12. */ public class MyApplication extends Application{ @Override public void onCreate() { super.onCreate(); //初始化IamgeLoader //获取sd卡根目录路径 File files = new File("/sdcard/Rimg"); initImageLoader(getApplicationContext(),files); } public static void initImageLoader(Context context, File file) { // This configuration tuning is custom. You can tune every option, you may tune some of them, // or you can create default configuration by // ImageLoaderConfiguration.createDefault(this); // method. ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(context); config.threadPriority(Thread.NORM_PRIORITY - 2); config.denyCacheImageMultipleSizesInMemory(); config.diskCacheFileNameGenerator(new Md5FileNameGenerator()); config.diskCacheSize(50 * 1024 * 1024); // 50 MiB config.tasksProcessingOrder(QueueProcessingType.LIFO); config.writeDebugLogs(); // Remove for release app config .diskCache(new UnlimitedDiskCache(file));//UnlimitedDiskCache 限制这个图片的缓存路径 config .diskCacheFileCount(50);//配置sdcard缓存文件的数量 // Initialize ImageLoader with configuration. ImageLoader.getInstance().init(config.build()); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } @Override public void onLowMemory() { super.onLowMemory(); } }WebActivty:
package com.bawei.com.myapplication; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; public class WebActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_web); WebView web = findViewById(R.id.web); Intent intent = getIntent(); String url = intent.getStringExtra("url"); web.loadUrl(url); web.setWebViewClient(new WebViewClient()); WebSettings settings = web.getSettings(); settings.setJavaScriptCanOpenWindowsAutomatically(true); settings.setJavaScriptEnabled(true); } }
布局文件:
fragment:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/frangment_lv" android:layout_width="match_parent" android:layout_height="match_parent"></ListView> </LinearLayout>item:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <RelativeLayout android:layout_width="0dp" android:layout_height="100dp" android:layout_weight="2" android:orientation="vertical"> <TextView android:id="@+id/item_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="20sp" /> <TextView android:id="@+id/item_time" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" /> </RelativeLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="horizontal"> <ImageView android:id="@+id/item_img" android:layout_width="match_parent" android:layout_height="101dp" /> </LinearLayout> </LinearLayout> </RelativeLayout>web:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.bawei.com.myapplication.WebActivity"> <WebView android:id="@+id/web" android:layout_width="match_parent" android:layout_height="match_parent"></WebView> </RelativeLayout>
注意:
以上代码可实现一个今日头条的小Demo