仿今日頭條頂部導航效果
之前發現很多人在群裏麵、論壇上求網易新聞客戶端的源碼,之後我就去下了個網易新聞客戶端和今日頭條新聞客戶端,發現他們的大體是一樣的,於是在最近的空閑時間,便去琢磨如何去實現這樣一個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"屬性:
- <style name="AppTheme" parent="AppBaseTheme">
- <item name="android:windowNoTitle">true</item>
- </style>
- 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();//跳轉
- }
- });
下麵就首先來實現上部欄目拖動這個效果:
大體思路結構圖:
整體的布局文件是如下這樣:
- <LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
- xmlns:tools="https://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來判斷滾動,如果滾動時候不是在最左邊,顯示左邊陰影,不是在最右邊,顯示右邊陰影。
- 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:
- 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;
- }
- }
- 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);
- }
- <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源碼
最後更新:2017-04-03 12:56:18