前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >仿今日头条顶部导航效果

仿今日头条顶部导航效果

作者头像
xiangzhihong
发布2018-01-29 15:16:35
2.1K0
发布2018-01-29 15:16:35
举报
文章被收录于专栏:向治洪向治洪

 之前发现很多人在群里面、论坛上求网易新闻客户端的源码,之后我就去下了个网易新闻客户端和今日头条新闻客户端,发现他们的大体是一样的,于是在最近的空闲时间,便去琢磨如何去实现这样一个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
复制
<style name="AppTheme" parent="AppBaseTheme">  
    <item name="android:windowNoTitle">true</item>  
</style>  

三.开始开发

设置欢迎界面的调整动画,2秒

代码语言:java
复制
start_anima = new AlphaAnimation(0.3f, 1.0f);  
start_anima.setDuration(2000);  
view.startAnimation(start_anima);  
start_anima.setAnimationListener(new AnimationListener() {  
 
 @Override 
 public void onAnimationStart(Animation animation) {  
 // TODO Auto-generated method stub 
 
    }  
 
 @Override 
 public void onAnimationRepeat(Animation animation) {  
 // TODO Auto-generated method stub 
 
    }  
 
 @Override 
 public void onAnimationEnd(Animation animation) {  
 // TODO Auto-generated method stub 
        redirectTo();//跳转 
    }  
});  

之后便是主界面:

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

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

大体思路结构图:

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

代码语言:java
复制
<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" >  
 
    <include layout="@layout/main_head" />  
 
    <LinearLayout  
        android:layout_width="match_parent" 
        android:layout_height="40.0dip" 
        android:background="#fff3f3f3" 
        android:orientation="horizontal" >  
 
        <RelativeLayout  
            android:id="@+id/rl_column" 
            android:layout_width="match_parent" 
            android:layout_height="40.0dip" 
            android:layout_weight="1.0" >  
 
            <com.topnews.view.ColumnHorizontalScrollView  
                android:id="@+id/mColumnHorizontalScrollView" 
                android:layout_width="match_parent" 
                android:layout_height="40.0dip" 
                android:scrollbars="none" >  
 
                <LinearLayout  
                    android:id="@+id/mRadioGroup_content" 
                    android:layout_width="fill_parent" 
                    android:layout_height="40.0dip" 
                    android:layout_centerVertical="true" 
                    android:gravity="center_vertical" 
                    android:orientation="horizontal" 
                    android:paddingLeft="10.0dip" 
                    android:paddingRight="10.0dip" />  
            </com.topnews.view.ColumnHorizontalScrollView>  
 
            <ImageView  
                android:id="@+id/shade_left" 
                android:layout_width="10.0dip" 
                android:layout_height="40.0dip" 
                android:layout_alignParentLeft="true" 
                android:layout_centerVertical="true" 
                android:background="@drawable/channel_leftblock" 
                android:visibility="gone" />  
 
            <ImageView  
                android:id="@+id/shade_right" 
                android:layout_width="10.0dip" 
                android:layout_height="40.0dip" 
                android:layout_alignParentRight="true" 
                android:layout_centerVertical="true" 
                android:background="@drawable/channel_rightblock" 
                android:visibility="visible" />  
        </RelativeLayout>  
 
        <LinearLayout  
            android:id="@+id/ll_more_columns" 
            android:layout_width="wrap_content" 
            android:layout_height="40.0dip" >  
 
            <ImageView  
                android:id="@+id/button_more_columns" 
                android:layout_width="40.0dip" 
                android:layout_height="40.0dip" 
                android:layout_gravity="center_vertical" 
                android:src="@drawable/channel_glide_day_bg" />  
        </LinearLayout>  
    </LinearLayout>  
 
    <View  
        android:id="@+id/category_line" 
        android:layout_width="fill_parent" 
        android:layout_height="0.5dip" 
        android:background="#ffdddddd" />  
 
    <android.support.v4.view.ViewPager  
        android:id="@+id/mViewPager" 
        android:layout_width="match_parent" 
        android:layout_height="match_parent" />  
 
</LinearLayout>  

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

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

代码语言:java
复制
public class ColumnHorizontalScrollView extends HorizontalScrollView {  
 /** 传入整体布局  */ 
 private View ll_content;  
 /** 传入更多栏目选择布局 */ 
 private View ll_more;  
 /** 传入拖动栏布局 */ 
 private View rl_column;  
 /** 左阴影图片 */ 
 private ImageView leftImage;  
 /** 右阴影图片 */ 
 private ImageView rightImage;  
 /** 屏幕宽度 */ 
 private int mScreenWitdh = 0;  
 /** 父类的活动activity */ 
 private Activity activity;  
 
 public ColumnHorizontalScrollView(Context context) {  
 super(context);  
    }  
 
 public ColumnHorizontalScrollView(Context context, AttributeSet attrs) {  
 super(context, attrs);  
    }  
 
 public ColumnHorizontalScrollView(Context context, AttributeSet attrs,  
 int defStyle) {  
 super(context, attrs, defStyle);  
    }  
 /**  
     * 在拖动的时候执行 
     * */ 
 @Override 
 protected void onScrollChanged(int paramInt1, int paramInt2, int paramInt3, int paramInt4) {  
 // TODO Auto-generated method stub 
 super.onScrollChanged(paramInt1, paramInt2, paramInt3, paramInt4);  
        shade_ShowOrHide();  
 if(!activity.isFinishing() && ll_content !=null && leftImage!=null && rightImage!=null && ll_more!=null && rl_column !=null){  
 if(ll_content.getWidth() <= mScreenWitdh){  
                leftImage.setVisibility(View.GONE);  
                rightImage.setVisibility(View.GONE);  
            }  
        }else{  
 return;  
        }  
 if(paramInt1 ==0){  
            leftImage.setVisibility(View.GONE);  
            rightImage.setVisibility(View.VISIBLE);  
 return;  
        }  
 if(ll_content.getWidth() - paramInt1 + ll_more.getWidth() + rl_column.getLeft() == mScreenWitdh){  
            leftImage.setVisibility(View.VISIBLE);  
            rightImage.setVisibility(View.GONE);  
 return;  
        }  
        leftImage.setVisibility(View.VISIBLE);  
       <span style="white-space:pre">   </span>rightImage.setVisibility(View.VISIBLE);  
    }  
 /**  
     * 传入父类布局中的资源文件 
     * */ 
 public void setParam(Activity activity, int mScreenWitdh,View paramView1,ImageView paramView2, ImageView paramView3 ,View paramView4,View paramView5){  
 this.activity = activity;  
 this.mScreenWitdh = mScreenWitdh;  
        ll_content = paramView1;  
        leftImage = paramView2;  
        rightImage = paramView3;  
        ll_more = paramView4;  
        rl_column = paramView5;  
    }  
 /**  
     * 判断左右阴影的显示隐藏效果 
     * */ 
 public void shade_ShowOrHide() {  
 if (!activity.isFinishing() && ll_content != null) {  
            measure(0, 0);  
 //如果整体宽度小于屏幕宽度的话,那左右阴影都隐藏 
 if (mScreenWitdh >= getMeasuredWidth()) {  
                leftImage.setVisibility(View.GONE);  
                rightImage.setVisibility(View.GONE);  
            }  
        } else {  
 return;  
        }  
 //如果滑动在最左边时候,左边阴影隐藏,右边显示 
 if (getLeft() == 0) {  
            leftImage.setVisibility(View.GONE);  
            rightImage.setVisibility(View.VISIBLE);  
 return;  
        }  
 //如果滑动在最右边时候,左边阴影显示,右边隐藏 
 if (getRight() == getMeasuredWidth() - mScreenWitdh) {  
            leftImage.setVisibility(View.VISIBLE);  
            rightImage.setVisibility(View.GONE);  
 return;  
        }  
 //否则,说明在中间位置,左、右阴影都显示 
        leftImage.setVisibility(View.VISIBLE);  
        rightImage.setVisibility(View.VISIBLE);  
    }  
}  

之后

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

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

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

代码语言:java
复制
public class NewsFragmentPagerAdapter extends FragmentPagerAdapter {  
 private ArrayList<Fragment> fragments;  
 private FragmentManager fm;  
 
 public NewsFragmentPagerAdapter(FragmentManager fm) {  
 super(fm);  
 this.fm = fm;  
    }  
 
 public NewsFragmentPagerAdapter(FragmentManager fm,  
            ArrayList<Fragment> fragments) {  
 super(fm);  
 this.fm = fm;  
 this.fragments = fragments;  
    }  
 
 @Override 
 public int getCount() {  
 return fragments.size();  
    }  
 
 @Override 
 public Fragment getItem(int position) {  
 return fragments.get(position);  
    }  
 
 @Override 
 public int getItemPosition(Object object) {  
 return POSITION_NONE;  
    }  
 
 public void setFragments(ArrayList<Fragment> fragments) {  
 if (this.fragments != null) {  
            FragmentTransaction ft = fm.beginTransaction();  
 for (Fragment f : this.fragments) {  
                ft.remove(f);  
            }  
            ft.commit();  
            ft = null;  
            fm.executePendingTransactions();  
        }  
 this.fragments = fragments;  
        notifyDataSetChanged();  
    }  
 
 @Override 
 public Object instantiateItem(ViewGroup container, final int position) {  
        Object obj = super.instantiateItem(container, position);  
 return obj;  
    }  
 
}  

之后添加栏目ITEM:

代码语言:java
复制
int count =  newsClassify.size();  
 for(int i = 0; i< count; i++){  
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mItemWidth , LayoutParams.WRAP_CONTENT);  
        params.leftMargin = 10;  
        params.rightMargin = 10;  
        TextView localTextView = new TextView(this);  
        localTextView.setTextAppearance(this, R.style.top_category_scroll_view_item_text);  
        localTextView.setBackgroundResource(R.drawable.radio_buttong_bg);  
        localTextView.setGravity(Gravity.CENTER);  
        localTextView.setPadding(5, 0, 5, 0);  
        localTextView.setId(i);  
        localTextView.setText(newsClassify.get(i).getTitle());  
        localTextView.setTextColor(getResources().getColorStateList(R.color.top_category_scroll_text_color_day));  
 if(columnSelectIndex == i){  
            localTextView.setSelected(true);  
        }  
        localTextView.setOnClickListener(new OnClickListener() {  
 
 @Override 
 public void onClick(View v) {  
 for(int i = 0;i < mRadioGroup_content.getChildCount();i++){  
                      View localView = mRadioGroup_content.getChildAt(i);  
 if (localView != v)  
                          localView.setSelected(false);  
 else{  
                          localView.setSelected(true);  
                          mViewPager.setCurrentItem(i);  
                      }  
                  }  
                  Toast.makeText(getApplicationContext(), newsClassify.get(v.getId()).getTitle(), Toast.LENGTH_SHORT).show();  
            }  
        });  
        mRadioGroup_content.addView(localTextView, i ,params);  
    }  

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

代码语言:js
复制
<span style="white-space:pre">  </span>/**  
     *  选择的Column里面的Tab 
     * */ 
 private void selectTab(int tab_postion) {  
        columnSelectIndex = tab_postion;  
 for (int i = 0; i < mRadioGroup_content.getChildCount(); i++) {  
            View checkView = mRadioGroup_content.getChildAt(tab_postion);  
 int k = checkView.getMeasuredWidth();  
 int l = checkView.getLeft();  
 int i2 = l + k / 2 - mScreenWidth / 2;  
 // rg_nav_content.getParent()).smoothScrollTo(i2, 0); 
            mColumnHorizontalScrollView.smoothScrollTo(i2, 0);  
 // mColumnHorizontalScrollView.smoothScrollTo((position - 2) * 
 // mItemWidth , 0); 
        }  
 //判断是否选中 
 for (int j = 0; j <  mRadioGroup_content.getChildCount(); j++) {  
            View checkView = mRadioGroup_content.getChildAt(j);  
 boolean ischeck;  
 if (j == tab_postion) {  
                ischeck = true;  
            } else {  
                ischeck = false;  
            }  
            checkView.setSelected(ischeck);  
        }  
    }  

完成的效果如下:

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2014-04-17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档