在模仿中循序渐进,以程序员角度去看待每一个APP是如何实现的,它有什么优缺点,并从中提升自己。

之前发现很多人在群里面、论坛上求网易新闻客户端的源码,之后我就去下了个网易新闻客户端和今日头条新闻客户端,发现他们的大体是一样的,于是在最近的空闲时间,便去琢磨如何去实现这样一个APP。

要知道它们是如何实现的,用到了什么第三方库文件,反编译便是很好的一个了解方法,如果你想要了解如何反编译可以点击这个链接:反编译就这么简单

只是一般的APK打包后都是被混淆过的,所以没那么好了解他的每个界面是如何实现的,没事,那就自己慢慢摸索或则从它的资源文件中提取布局了解下整体的大概情况。

我通过反编译 --今日头条:

知道了它用到的架包有,提取了有用的部分:

1.Android-support-v4.jar (最常用的官方架包之一)

2.android-support-v7.jar (主要用于ActionBar的低版本兼容)

3.handmark.pulltorefresh.library  (图片的下拉刷新包)

4.slidingmenu.lib  (侧拉菜单包)   使用方法配置以及下载:点击这里

5.umeng (友盟的官方架包)

自己要在加用上的架包有:

1.Android-Universal-Image-Loader  (图片的异步加载包)   使用方法配置以及下载:点击这里

注:发现架包中有aaa什么的命名,说明它被混淆过,所以要想进一步获取它的源码很困难,只能按照自己的思路去走。

好的,大体了解了它的整体结构,下面就开始它是如何开发的把:

注:本代码内用到的资源文件和属性配置部分从APK反编译的资源(SRC文件)中提取,为了达到更好的实现效果。

一.首先构建大体的框架,架包等用到的时候在导入

命名规范可以参考:android命名规范

二.进行配置

首先去掉应用的title栏目:

采取修改AndroidManifest.xml文件中application的android:theme="@style/AppTheme"属性:

[java] view plaincopy
  1. <style name="AppTheme" parent="AppBaseTheme">
  2. <item name="android:windowNoTitle">true</item>
  3. </style>
三.开始开发
设置欢迎界面的调整动画,2秒
[java] view plaincopy
  1. start_anima = new AlphaAnimation(0.3f, 1.0f);
  2. start_anima.setDuration(2000);
  3. view.startAnimation(start_anima);
  4. start_anima.setAnimationListener(new AnimationListener() {
  5. @Override
  6. public void onAnimationStart(Animation animation) {
  7. // TODO Auto-generated method stub
  8. }
  9. @Override
  10. public void onAnimationRepeat(Animation animation) {
  11. // TODO Auto-generated method stub
  12. }
  13. @Override
  14. public void onAnimationEnd(Animation animation) {
  15. // TODO Auto-generated method stub
  16. redirectTo();//跳转
  17. }
  18. });

之后便是主界面:

可以发现主界面上方的栏目栏是可以横向拖动的,并且选择。

下面就首先来实现上部栏目拖动这个效果:

大体思路结构图:

整体的布局文件是如下这样:

[java] view plaincopy
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical" >
  6. <include layout="@layout/main_head" />
  7. <LinearLayout
  8. android:layout_width="match_parent"
  9. android:layout_height="40.0dip"
  10. android:background="#fff3f3f3"
  11. android:orientation="horizontal" >
  12. <RelativeLayout
  13. android:id="@+id/rl_column"
  14. android:layout_width="match_parent"
  15. android:layout_height="40.0dip"
  16. android:layout_weight="1.0" >
  17. <com.topnews.view.ColumnHorizontalScrollView
  18. android:id="@+id/mColumnHorizontalScrollView"
  19. android:layout_width="match_parent"
  20. android:layout_height="40.0dip"
  21. android:scrollbars="none" >
  22. <LinearLayout
  23. android:id="@+id/mRadioGroup_content"
  24. android:layout_width="fill_parent"
  25. android:layout_height="40.0dip"
  26. android:layout_centerVertical="true"
  27. android:gravity="center_vertical"
  28. android:orientation="horizontal"
  29. android:paddingLeft="10.0dip"
  30. android:paddingRight="10.0dip" />
  31. </com.topnews.view.ColumnHorizontalScrollView>
  32. <ImageView
  33. android:id="@+id/shade_left"
  34. android:layout_width="10.0dip"
  35. android:layout_height="40.0dip"
  36. android:layout_alignParentLeft="true"
  37. android:layout_centerVertical="true"
  38. android:background="@drawable/channel_leftblock"
  39. android:visibility="gone" />
  40. <ImageView
  41. android:id="@+id/shade_right"
  42. android:layout_width="10.0dip"
  43. android:layout_height="40.0dip"
  44. android:layout_alignParentRight="true"
  45. android:layout_centerVertical="true"
  46. android:background="@drawable/channel_rightblock"
  47. android:visibility="visible" />
  48. </RelativeLayout>
  49. <LinearLayout
  50. android:id="@+id/ll_more_columns"
  51. android:layout_width="wrap_content"
  52. android:layout_height="40.0dip" >
  53. <ImageView
  54. android:id="@+id/button_more_columns"
  55. android:layout_width="40.0dip"
  56. android:layout_height="40.0dip"
  57. android:layout_gravity="center_vertical"
  58. android:src="@drawable/channel_glide_day_bg" />
  59. </LinearLayout>
  60. </LinearLayout>
  61. <View
  62. android:id="@+id/category_line"
  63. android:layout_width="fill_parent"
  64. android:layout_height="0.5dip"
  65. android:background="#ffdddddd" />
  66. <android.support.v4.view.ViewPager
  67. android:id="@+id/mViewPager"
  68. android:layout_width="match_parent"
  69. android:layout_height="match_parent" />
  70. </LinearLayout>

由于发现HorizontalScrollView左右拖动的时候没有那种阴影效果,所以在这里,我们发现了头条的资源文件下有这么2个文件:

这个就是它在白天模式和黑夜模式下用的阴影图片。那我们可以采取重写HorizontalScrollView来判断滚动,如果滚动时候不是在最左边,显示左边阴影,不是在最右边,显示右边阴影。

[java] view plaincopy
  1. public class ColumnHorizontalScrollView extends HorizontalScrollView {
  2. /** 传入整体布局  */
  3. private View ll_content;
  4. /** 传入更多栏目选择布局 */
  5. private View ll_more;
  6. /** 传入拖动栏布局 */
  7. private View rl_column;
  8. /** 左阴影图片 */
  9. private ImageView leftImage;
  10. /** 右阴影图片 */
  11. private ImageView rightImage;
  12. /** 屏幕宽度 */
  13. private int mScreenWitdh = 0;
  14. /** 父类的活动activity */
  15. private Activity activity;
  16. public ColumnHorizontalScrollView(Context context) {
  17. super(context);
  18. }
  19. public ColumnHorizontalScrollView(Context context, AttributeSet attrs) {
  20. super(context, attrs);
  21. }
  22. public ColumnHorizontalScrollView(Context context, AttributeSet attrs,
  23. int defStyle) {
  24. super(context, attrs, defStyle);
  25. }
  26. /**
  27. * 在拖动的时候执行
  28. * */
  29. @Override
  30. protected void onScrollChanged(int paramInt1, int paramInt2, int paramInt3, int paramInt4) {
  31. // TODO Auto-generated method stub
  32. super.onScrollChanged(paramInt1, paramInt2, paramInt3, paramInt4);
  33. shade_ShowOrHide();
  34. if(!activity.isFinishing() && ll_content !=null && leftImage!=null && rightImage!=null && ll_more!=null && rl_column !=null){
  35. if(ll_content.getWidth() <= mScreenWitdh){
  36. leftImage.setVisibility(View.GONE);
  37. rightImage.setVisibility(View.GONE);
  38. }
  39. }else{
  40. return;
  41. }
  42. if(paramInt1 ==0){
  43. leftImage.setVisibility(View.GONE);
  44. rightImage.setVisibility(View.VISIBLE);
  45. return;
  46. }
  47. if(ll_content.getWidth() - paramInt1 + ll_more.getWidth() + rl_column.getLeft() == mScreenWitdh){
  48. leftImage.setVisibility(View.VISIBLE);
  49. rightImage.setVisibility(View.GONE);
  50. return;
  51. }
  52. leftImage.setVisibility(View.VISIBLE);
  53. <span style="white-space:pre">   </span>rightImage.setVisibility(View.VISIBLE);
  54. }
  55. /**
  56. * 传入父类布局中的资源文件
  57. * */
  58. public void setParam(Activity activity, int mScreenWitdh,View paramView1,ImageView paramView2, ImageView paramView3 ,View paramView4,View paramView5){
  59. this.activity = activity;
  60. this.mScreenWitdh = mScreenWitdh;
  61. ll_content = paramView1;
  62. leftImage = paramView2;
  63. rightImage = paramView3;
  64. ll_more = paramView4;
  65. rl_column = paramView5;
  66. }
  67. /**
  68. * 判断左右阴影的显示隐藏效果
  69. * */
  70. public void shade_ShowOrHide() {
  71. if (!activity.isFinishing() && ll_content != null) {
  72. measure(0, 0);
  73. //如果整体宽度小于屏幕宽度的话,那左右阴影都隐藏
  74. if (mScreenWitdh >= getMeasuredWidth()) {
  75. leftImage.setVisibility(View.GONE);
  76. rightImage.setVisibility(View.GONE);
  77. }
  78. } else {
  79. return;
  80. }
  81. //如果滑动在最左边时候,左边阴影隐藏,右边显示
  82. if (getLeft() == 0) {
  83. leftImage.setVisibility(View.GONE);
  84. rightImage.setVisibility(View.VISIBLE);
  85. return;
  86. }
  87. //如果滑动在最右边时候,左边阴影显示,右边隐藏
  88. if (getRight() == getMeasuredWidth() - mScreenWitdh) {
  89. leftImage.setVisibility(View.VISIBLE);
  90. rightImage.setVisibility(View.GONE);
  91. return;
  92. }
  93. //否则,说明在中间位置,左、右阴影都显示
  94. leftImage.setVisibility(View.VISIBLE);
  95. rightImage.setVisibility(View.VISIBLE);
  96. }
  97. }

之后

private ArrayList<NewsClassify> newsClassify=new ArrayList<NewsClassify>();

根据newsClassify这个栏目分类列表里面的数量进行添加栏目。(这里首先采用了自己限定的ITEM,而没有进行数据库的操作,以后加上)

ViewPage的适配器NewsFragmentPagerAdapter,通过ViewPage切换对应栏目的的Fragment:

[java] view plaincopy
  1. public class NewsFragmentPagerAdapter extends FragmentPagerAdapter {
  2. private ArrayList<Fragment> fragments;
  3. private FragmentManager fm;
  4. public NewsFragmentPagerAdapter(FragmentManager fm) {
  5. super(fm);
  6. this.fm = fm;
  7. }
  8. public NewsFragmentPagerAdapter(FragmentManager fm,
  9. ArrayList<Fragment> fragments) {
  10. super(fm);
  11. this.fm = fm;
  12. this.fragments = fragments;
  13. }
  14. @Override
  15. public int getCount() {
  16. return fragments.size();
  17. }
  18. @Override
  19. public Fragment getItem(int position) {
  20. return fragments.get(position);
  21. }
  22. @Override
  23. public int getItemPosition(Object object) {
  24. return POSITION_NONE;
  25. }
  26. public void setFragments(ArrayList<Fragment> fragments) {
  27. if (this.fragments != null) {
  28. FragmentTransaction ft = fm.beginTransaction();
  29. for (Fragment f : this.fragments) {
  30. ft.remove(f);
  31. }
  32. ft.commit();
  33. ft = null;
  34. fm.executePendingTransactions();
  35. }
  36. this.fragments = fragments;
  37. notifyDataSetChanged();
  38. }
  39. @Override
  40. public Object instantiateItem(ViewGroup container, final int position) {
  41. Object obj = super.instantiateItem(container, position);
  42. return obj;
  43. }
  44. }

之后添加栏目ITEM:

[java] view plaincopy
  1. int count =  newsClassify.size();
  2. for(int i = 0; i< count; i++){
  3. LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mItemWidth , LayoutParams.WRAP_CONTENT);
  4. params.leftMargin = 10;
  5. params.rightMargin = 10;
  6. TextView localTextView = new TextView(this);
  7. localTextView.setTextAppearance(this, R.style.top_category_scroll_view_item_text);
  8. localTextView.setBackgroundResource(R.drawable.radio_buttong_bg);
  9. localTextView.setGravity(Gravity.CENTER);
  10. localTextView.setPadding(5, 0, 5, 0);
  11. localTextView.setId(i);
  12. localTextView.setText(newsClassify.get(i).getTitle());
  13. localTextView.setTextColor(getResources().getColorStateList(R.color.top_category_scroll_text_color_day));
  14. if(columnSelectIndex == i){
  15. localTextView.setSelected(true);
  16. }
  17. localTextView.setOnClickListener(new OnClickListener() {
  18. @Override
  19. public void onClick(View v) {
  20. for(int i = 0;i < mRadioGroup_content.getChildCount();i++){
  21. View localView = mRadioGroup_content.getChildAt(i);
  22. if (localView != v)
  23. localView.setSelected(false);
  24. else{
  25. localView.setSelected(true);
  26. mViewPager.setCurrentItem(i);
  27. }
  28. }
  29. Toast.makeText(getApplicationContext(), newsClassify.get(v.getId()).getTitle(), Toast.LENGTH_SHORT).show();
  30. }
  31. });
  32. mRadioGroup_content.addView(localTextView, i ,params);
  33. }

之后根据选择栏目的来调整ColumnHorizontalScrollView中的位置

[java] view plaincopy
  1. <span style="white-space:pre">  </span>/**
  2. *  选择的Column里面的Tab
  3. * */
  4. private void selectTab(int tab_postion) {
  5. columnSelectIndex = tab_postion;
  6. for (int i = 0; i < mRadioGroup_content.getChildCount(); i++) {
  7. View checkView = mRadioGroup_content.getChildAt(tab_postion);
  8. int k = checkView.getMeasuredWidth();
  9. int l = checkView.getLeft();
  10. int i2 = l + k / 2 - mScreenWidth / 2;
  11. // rg_nav_content.getParent()).smoothScrollTo(i2, 0);
  12. mColumnHorizontalScrollView.smoothScrollTo(i2, 0);
  13. // mColumnHorizontalScrollView.smoothScrollTo((position - 2) *
  14. // mItemWidth , 0);
  15. }
  16. //判断是否选中
  17. for (int j = 0; j <  mRadioGroup_content.getChildCount(); j++) {
  18. View checkView = mRadioGroup_content.getChildAt(j);
  19. boolean ischeck;
  20. if (j == tab_postion) {
  21. ischeck = true;
  22. } else {
  23. ischeck = false;
  24. }
  25. checkView.setSelected(ischeck);
  26. }
  27. }

完成的效果如下:

更多注释和实现方法可以查看DEMO源码文件,源码下载地址 :  DEMO源码

第2篇已经优化完成点击以下链接:

(android高仿系列)今日头条 --新闻阅读器 (二)

(android高仿系列)今日头条 --新闻阅读器 (一)相关推荐

  1. (android高仿系列)今日头条 --新闻阅读器 (三) 完结 、总结 篇

    从写第一篇今日头条高仿系列开始,到现在已经过去了1个多月了,其实大体都做好了,就是迟迟没有放出来,因为我觉得,做这个东西也是有个过程的,我想把这个模仿中一步一步学习的过程,按照自己的思路写下来,在根据 ...

  2. (android高仿系列)今日头条 --新闻阅读器 (二)

    高仿今日头条 --- 第一篇:(android高仿系列)今日头条 --新闻阅读器 (一) 上次,已经完成了头部新闻分类栏目的拖动效果. 这篇文章是继续去完善APP 今日头条  这个新闻阅读器的其他功能 ...

  3. android高仿今日头条 --新闻阅读器

    摘要: 开发流程 第一篇:(android高仿系列)今日头条 --新闻阅读器 (一) 涉及到的知识点有 1.slidingmenu.lib  (侧拉菜单包)   使用方法配置以及下载:点击这里   实 ...

  4. 今日头条 --新闻阅读器

    高仿今日头条 --- 第一篇:(android高仿系列)今日头条 --新闻阅读器 (一) 上次,已经完成了头部新闻分类栏目的拖动效果. 这篇文章是继续去完善APP 今日头条  这个新闻阅读器的其他功能 ...

  5. 今日头条 --新闻阅读器 (二)

    版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 高仿今日头条 --- 第一篇:(android高仿系列)今日头条 --新闻阅读器 (一) 上次,已经完成了头部新闻分类栏目的拖动 ...

  6. 今日头条新闻阅读器 (三) 完结 、总结 篇

    从写第一篇今日头条高仿系列开始,到现在已经过去了1个多月了,其实大体都做好了,就是迟迟没有放出来,因为我觉得,做这个东西也是有个过程的,我想把这个模仿中一步一步学习的过程,按照自己的思路写下来,在根据 ...

  7. Android 仿 新闻阅读器 菜单弹出效果(附源码DEMO)

    这一系列博文都是:(android高仿系列)今日头条 --新闻阅读器 (一) 开发中碰到问题之后实现的,觉得可能有的开发者用的到或则希望独立成一个小功能DEMO,所以就放出来这么一个DEMO. 原本觉 ...

  8. [Android] Android 手机下 仿 今日头条 新闻客户端

    利用一个月的时间,自学了 Android 开发 ,为了检验学习成果,特意 开发了这个  仿 今日头条 新闻客户端 AppNews 包括图文新闻+视频新闻+图片新闻 预览演示如下: 功能说明: 1)底部 ...

  9. android高仿京东快报(垂直循环滚动新闻栏)

    的android高仿京东快报(垂直循环滚动新闻栏) 标签: 机器人 2016年3月20日03:08 2676阅读人 评论(15)收藏举报    分类: 机器人(71)  版权声明:本文为博主原创文章, ...

最新文章

  1. Linux那些事儿 之 戏说USB(25)设备的生命线(八)
  2. Citrix XenServer 关键配置文件
  3. HTML代码编写规范
  4. 【SpringMVC 之应用篇】 1_SpringMVC入门 —— 第一个 Spring MVC 程序
  5. 【TypeScript系列教程14】Array数组对象的常见的方法
  6. IO流配置文件,键值对Properties 的读取
  7. c语言错误解析-变量声明
  8. testlink php nginx,linux环境部署testlink步骤说明
  9. java字符串转字符串数组_Java字符串数组到字符串
  10. orangepi获取cpu温度
  11. CTF—攻防练习之HTTP—命令执行漏洞
  12. 需求分析中常用的图形工具
  13. 清明上河图对计算机技术的启发,《清明上河图》鉴定故事的启示
  14. 计算机功能室设备器材清单,办公用品清单
  15. 用python做外贸
  16. 保证金监控中心保证期货开户和交易记录
  17. 【程序员如何买基金 三】场内场外交易的区别
  18. 服务器摆放需要预留U位么_办公沙发摆放有何讲究?
  19. 【NLP】第9章 匹配分词器和数据集
  20. 【vue】avue-crud配置大全-持续更新

热门文章

  1. c语言迷宫闯关游戏大全,C语言写出的迷宫闯关游戏代码.doc
  2. SQL Server数据库SP命令祥解
  3. eBPF 入门开发实践指南三:在 eBPF 中使用 fentry 监测捕获 unlink 系统调用
  4. HDU4507吉哥系列故事――恨7不成妻
  5. 分析:全球债市预警经济衰退风险 未来通胀预期大跌
  6. 《儿童教育心理学》读书笔记
  7. 一对一视频直播源码实现网络中一对一视频聊天
  8. 美国一年就印了6个币圈市值出来,钱都去哪了?
  9. Mybatis 查询返回List集合
  10. quot;虽千万人吾往矣quot;出处