底部导航栏(自定义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监听,实现了滑动时改变顶部导航栏的标题。



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值