底部導航欄(自定義View+ViewPager實現) android項目詳解

項目地址:https://github.com/blanks1314/sysnc_android

基於公司SDK做的一個支付集成demo,僅以此記錄過程中用到的一些技術,望與君共勉之!


效果圖:









首先先介紹首頁底部導航欄與頂部導航欄+中間viewpager的實現:

借鑑該編博客:http://blog.csdn.net/maosidiaoxian/article/details/38864679 (其他相關接口,和style請閱讀該篇博客,本文主要實現的是底部導航、中間viewpager和頂部菜單的聯動)快速實現底部菜單加上頂部導航欄,加上一些自己的定製,具體參考以下代碼


以下是IconTabPageIndicator類:

package com.wosai.upaydemo.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.wosai.upaydemo.R;

public class IconTabPageIndicator extends LinearLayout implements PageIndicator {
	/**
	 * Title text used when no title is provided by the adapter.
	 */
	private static final CharSequence EMPTY_TITLE = "";

	private String[] mTitles;
	private TextView mView;

	/**
	 * Interface for a callback when the selected tab has been reselected.
	 */
	public interface OnTabReselectedListener {
		/**
		 * Callback when the selected tab has been reselected.
		 * 
		 * @param position
		 *            Position of the current center item.
		 */
		void onTabReselected(int position);
	}

	private Runnable mTabSelector;

	private final View.OnClickListener mTabClickListener = new View.OnClickListener() {
		public void onClick(View view) {
			TabView tabView = (TabView) view;
			final int oldSelected = mViewPager.getCurrentItem();
			final int newSelected = tabView.getIndex();
			mViewPager.setCurrentItem(newSelected, false);
			if (oldSelected == newSelected && mTabReselectedListener != null) {
				mTabReselectedListener.onTabReselected(newSelected);
			}
			if (mTitles.length > 0) {
				if (mTitles.length == mViewPager.getAdapter().getCount()) {
					mView.setText(mTitles[newSelected]);
				} else {
					throw new RuntimeException(
							"lengthException:titles length != viewpager child count,Please check your title length of an array and viewpager child count the length!");
				}
			}
		}
	};

	private final LinearLayout mTabLayout;

	private ViewPager mViewPager;
	private ViewPager.OnPageChangeListener mListener;

	private int mSelectedTabIndex;

	private OnTabReselectedListener mTabReselectedListener;

	private int mTabWidth;

	public IconTabPageIndicator(Context context) {
		this(context, null);
	}

	@SuppressLint("NewApi")
	public IconTabPageIndicator(Context context, AttributeSet attrs) {
		super(context, attrs);
		setHorizontalScrollBarEnabled(false);

		mTabLayout = new LinearLayout(context, null, R.attr.tabPageIndicator);
		addView(mTabLayout, new ViewGroup.LayoutParams(
				LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
	}

	public void setOnTabReselectedListener(OnTabReselectedListener listener) {
		mTabReselectedListener = listener;
	}

	@Override
	public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		final int widthMode = View.MeasureSpec.getMode(widthMeasureSpec);
		final boolean lockedExpanded = widthMode == View.MeasureSpec.EXACTLY;

		final int childCount = mTabLayout.getChildCount();

		if (childCount > 1
				&& (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) {
			mTabWidth = MeasureSpec.getSize(widthMeasureSpec) / childCount;
		} else {
			mTabWidth = -1;
		}

		final int oldWidth = getMeasuredWidth();
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		final int newWidth = getMeasuredWidth();

		if (lockedExpanded && oldWidth != newWidth) {
			// Recenter the tab display if we're at a new (scrollable) size.
			setCurrentItem(mSelectedTabIndex);
		}
	}

	private void animateToTab(final int position) {
		if (mTabSelector != null) {
			removeCallbacks(mTabSelector);
		}
		mTabSelector = new Runnable() {
			public void run() {
				mTabSelector = null;
			}
		};
		post(mTabSelector);
	}

	@Override
	public void onAttachedToWindow() {
		super.onAttachedToWindow();
		if (mTabSelector != null) {
			// Re-post the selector we saved
			post(mTabSelector);
		}
	}

	@Override
	public void onDetachedFromWindow() {
		super.onDetachedFromWindow();
		if (mTabSelector != null) {
			removeCallbacks(mTabSelector);
		}
	}

	private void addTab(int index, CharSequence text, int iconResId) {
		final TabView tabView = new TabView(getContext());
		tabView.mIndex = index;
		tabView.setOnClickListener(mTabClickListener);
		tabView.setText(text);

		if (iconResId > 0) {
			tabView.setIcon(iconResId);
		}

		mTabLayout.addView(tabView, new LinearLayout.LayoutParams(0,
				LayoutParams.MATCH_PARENT, 1));
	}

	@Override
	public void onPageScrollStateChanged(int arg0) {
		if (mListener != null) {
			mListener.onPageScrollStateChanged(arg0);
		}
	}

	@Override
	public void onPageScrolled(int arg0, float arg1, int arg2) {
		if (mListener != null) {
			mListener.onPageScrolled(arg0, arg1, arg2);
		}
	}

	@Override
	public void onPageSelected(int arg0) {
		setCurrentItem(arg0);
		if (mListener != null) {
			mListener.onPageSelected(arg0);
		}
	}

	@Override
	public void setViewPager(ViewPager view) {
		if (mViewPager == view) {
			return;
		}
		if (mViewPager != null) {
			mViewPager.setOnPageChangeListener(null);
		}
		final PagerAdapter adapter = view.getAdapter();
		if (adapter == null) {
			throw new IllegalStateException(
					"ViewPager does not have adapter instance.");
		}
		mViewPager = view;
		view.setOnPageChangeListener(this);
		notifyDataSetChanged();
	}

	public void notifyDataSetChanged() {
		mTabLayout.removeAllViews();
		PagerAdapter adapter = mViewPager.getAdapter();
		IconPagerAdapter iconAdapter = null;
		if (adapter instanceof IconPagerAdapter) {
			iconAdapter = (IconPagerAdapter) adapter;
		}
		final int count = adapter.getCount();
		for (int i = 0; i < count; i++) {
			CharSequence title = adapter.getPageTitle(i);
			if (title == null) {
				title = EMPTY_TITLE;
			}
			int iconResId = 0;
			if (iconAdapter != null) {
				iconResId = iconAdapter.getIconResId(i);
			}
			addTab(i, title, iconResId);
		}
		if (mSelectedTabIndex > count) {
			mSelectedTabIndex = count - 1;
		}
		setCurrentItem(mSelectedTabIndex);
		requestLayout();
	}

	@Override
	public void setViewPager(ViewPager view, int initialPosition) {
		setViewPager(view);
		setCurrentItem(initialPosition);
	}

	@Override
	public void setCurrentItem(int item) {
		if (mViewPager == null) {
			throw new IllegalStateException("ViewPager has not been bound.");
		}
		mSelectedTabIndex = item;
		mViewPager.setCurrentItem(item, false);

		final int tabCount = mTabLayout.getChildCount();
		for (int i = 0; i < tabCount; i++) {
			final View child = mTabLayout.getChildAt(i);
			final boolean isSelected = (i == item);
			child.setSelected(isSelected);
			if (isSelected) {
				animateToTab(item);
			}
		}
	}

	@Override
	public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
		mListener = listener;
	}

	public void setTitles(String[] mTitles, TextView v) {
		this.mTitles = mTitles;
		this.mView = v;
	}

	@SuppressLint("NewApi")
	private class TabView extends LinearLayout {
		private int mIndex;
		private ImageView mImageView;
		private TextView mTextView;

		public TabView(Context context) {
			super(context, null, R.attr.tabView);
			View view = View.inflate(context, R.layout.tab_view, null);
			mImageView = (ImageView) view.findViewById(R.id.tab_image);
			mTextView = (TextView) view.findViewById(R.id.tab_text);
			this.addView(view);
		}

		@Override
		public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
			super.onMeasure(widthMeasureSpec, heightMeasureSpec);

			// Re-measure if we went beyond our maximum size.
			if (mTabWidth > 0) {
				super.onMeasure(MeasureSpec.makeMeasureSpec(mTabWidth,
						MeasureSpec.EXACTLY), heightMeasureSpec);
			}
		}

		public void setText(CharSequence text) {
			mTextView.setText(text);
		}

		public void setIcon(int resId) {
			if (resId > 0) {
				mImageView.setImageResource(resId);
			}
		}

		public int getIndex() {
			return mIndex;
		}
	}
}

修改的地方

這裏主要是限制傳入標題時,標題數量必須與頁面數量,以及底部按鈕數量相符,否則會拋出自己構建的RuntimeException,

	if (mTitles.length > 0) {
				if (mTitles.length == mViewPager.getAdapter().getCount()) {
					mView.setText(mTitles[newSelected]);
				} else {
					throw new RuntimeException(
							"lengthException:titles length != viewpager child count,Please check your title length of an array and viewpager child count the length!");
				}
			}

爲了實現點擊底部button同步改變頂部導航欄的標題:我給IconTabPageIndicator類添加了設置標題控件(暫時只支持傳入TextView,歡迎大家fork項目下來,修改的更加靈活,只是提供一種思路,實現底部導航和頂部菜單的聯動,其他需求可以根據自己實際情況定製)和標題名稱的接口:


	public void setTitles(String[] mTitles, TextView v) {
		this.mTitles = mTitles;
		this.mView = v;
	}


具體使用方法:

package com.wosai.upaydemo;

import java.util.ArrayList;
import java.util.List;

import android.app.Dialog;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.widget.TextView;

import cn.wosai.upay.OrderInfo;

import com.wosai.upaydemo.utils.ViewUtil;
import com.wosai.upaydemo.widget.BaseFragment;
import com.wosai.upaydemo.widget.FragmentAdapter;
import com.wosai.upaydemo.widget.IconTabPageIndicator;

public class HomeActivity extends FragmentActivity {

	private ViewPager mViewPager;
	private IconTabPageIndicator mIndicator;
	private TextView textTitle;
	private List<BaseFragment> fragments;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_home);
		initView();
	}

	/**
	 * 初始化界面
	 */
	private void initView() {
		mViewPager = (ViewPager) findViewById(R.id.vp_content);
		mIndicator = (IconTabPageIndicator) findViewById(R.id.indicator);
		textTitle = (TextView) findViewById(R.id.tv_title);
		FragmentAdapter adapter = new FragmentAdapter(initFragment(),
				getSupportFragmentManager());
		mViewPager.setAdapter(adapter);
		mIndicator.setViewPager(mViewPager);
		mIndicator.setTitles(new String[] { "設置", "銀聯支付", "支付寶支付", "微信支付",
				"交易記錄" }, textTitle);
		mIndicator.setOnPageChangeListener(new OnPageChangeListener() {

			@Override
			public void onPageSelected(int arg0) {
				// TODO Auto-generated method stub
			}

			@Override
			public void onPageScrolled(int arg0, float arg1, int arg2) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onPageScrollStateChanged(int index) {
				// TODO Auto-generated method stub
				switch (mViewPager.getCurrentItem()) {
				case 0:
					textTitle.setText("設置");
					break;
				case 1:
					textTitle.setText("銀聯支付");
					break;
				case 2:
					textTitle.setText("支付寶支付");
					break;
				case 3:
					textTitle.setText("微信支付");
					break;
				case 4:
					textTitle.setText("交易記錄");
					break;

				}
			}
		});

	}

	private List<BaseFragment> initFragment() {

		 fragments = new ArrayList<BaseFragment>();

		BaseFragment settingFragment = new SettingFragment();
		settingFragment.setTitle("設置");
		settingFragment.setIconId(R.drawable.setting);
		fragments.add(settingFragment);

		BaseFragment unionFragment = new LakalaFragment();
		unionFragment.setTitle("銀聯");
		unionFragment.setIconId(R.drawable.union_pay);
		fragments.add(unionFragment);

		BaseFragment alipayFragment = new AlipayFragment();
		alipayFragment.setTitle("Alipay");
		alipayFragment.setIconId(R.drawable.alipay);
		fragments.add(alipayFragment);

		BaseFragment wexinFragment = new WexinFragment();
		wexinFragment.setTitle("微信");
		wexinFragment.setIconId(R.drawable.wechat);
		fragments.add(wexinFragment);

		BaseFragment recordFragment = new RecordFragment();
		recordFragment.setTitle("記錄");
		recordFragment.setIconId(R.drawable.history);
		fragments.add(recordFragment);

		return fragments;

	}

	public interface IGetData {
		boolean checkData();
		OrderInfo getOrderInfo();
	}
	
	public SettingFragment getIGetData(){
		return (SettingFragment) fragments.get(0);
		
	}
}

該類中的viewpager監聽,實現了滑動時改變頂部導航欄的標題。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章