仿蘑菇街界面(2)

上一篇博客,博客地址http://blog.csdn.net/itbailei/article/details/38561297把基本的主界面框架已经搭建完毕,我们采用的基本框架为fragment进行页面之间的切换,底部菜单采用的是RadioButton。今天我们来重点来仿照一下第一个底部菜单“爱逛”,首先我们来分解一下功能区域:


1.功能区域分解

  (1) PageTabs左右切换菜单:这里我们使用第三方开源插件,不过需要自己进行修改,采用的是ViewPage进行页面的切换,左右滑动。

(2) 图片轮播:ViewGroup+Viewpage每一个ViewGroup存储一个按压效果的dot和一张图片,随着手指的滑动进行图片之间的切换,当然我们这里只使用五张图片。

(3)更新时间:这个不说了,就是设置时间,这里找不到图片我自己设定固定值,当然也可以通过代码设置。

(4)第一个列表,第二个列表,我们观察布局可知,下面2个布局的大小是分别占用了屏幕的一般,我们可以通过设置权值属性来设置大小,也就是

<span style="white-space:pre">		</span>android:layout_width="match_parent"
		android:layout_height="match_parent"
		android:layout_weight="2"


第一个布局是线性布局的,线性布局里面包括一个更新时间的一些TextView控件和一个GridView控件,第二个布局是一个单独的GridView控件

2.实现方式

(1) PageTabs:

第一个难点毋庸置疑就是PageTabs菜单,所幸这方面的开源组件挺多,我们可以使用郭霖大神推荐的PagerSlidingTabStrip,当然也要进行修改,修改包括横条的颜色。每一个PageTabs就是一个Fragment,因为放置这个PageTabs的本身就是一个Fragment,所以我们需要注意,在使用FragmentManager()的地方,必须要使用当前Fragment的子FragmentManager,否则会报错。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:background="#EEEEEE">
    
 <com.blog.mogujie.tool.PagerSlidingTabStrip
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="40dp" />

 <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
 
</LinearLayout>

PagerSlidingTabStrip为自定义控件,也就是第三方插件,ViewPager用来显示每一个页面的大小,但是注意到修改滚动条的长度,修改代码如下:

@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);

		if (isInEditMode() || tabCount == 0) {
			return;
		}

		final int height = getHeight();
		
		// draw underline
		rectPaint.setColor(underlineColor);
		canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint);

		// draw indicator line
		rectPaint.setColor(indicatorColor);

		// default: line below current tab
		View currentTab = tabsContainer.getChildAt(currentPosition);
		float lineLeft = currentTab.getLeft();
		float lineRight = currentTab.getRight();

		// if there is an offset, start interpolating left and right coordinates between current and next tab
		if (currentPositionOffset > 0f && currentPosition < tabCount - 1) {

			View nextTab = tabsContainer.getChildAt(currentPosition + 1);
			final float nextTabLeft = nextTab.getLeft();
			final float nextTabRight = nextTab.getRight();

			lineLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset) * lineLeft);
			lineRight = (currentPositionOffset * nextTabRight + (1f - currentPositionOffset) * lineRight);
		}

		canvas.drawRect(lineLeft+100, height - indicatorHeight, lineRight-100, height, rectPaint);

		// draw divider

		dividerPaint.setColor(dividerColor);
		for (int i = 0; i < tabCount - 1; i++) {
			View tab = tabsContainer.getChildAt(i);
			canvas.drawLine(tab.getRight(), dividerPadding, tab.getRight(), height - dividerPadding, dividerPaint);
		}
	}


主要看第这一行

canvas.drawRect(lineLeft+100, height - indicatorHeight, lineRight-100, height, rectPaint);

这行lineLeft+100,lineRight-100设置左右两边同时减小100的长度。

设置IndexFragment代码,该代码就是“精选”菜单区域Fragment,代码如下:

public class IndexFragment extends Fragment {
	private PagerSlidingTabStrip tabs;
	private DisplayMetrics dm;
	private String[] titles = { "精选", "搭配", "团购" };
	private ViewPager pager;
	private Fragment fragment;
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		dm = getResources().getDisplayMetrics();
		pager = (ViewPager) getView().findViewById(R.id.pager);
		tabs = (PagerSlidingTabStrip) getView().findViewById(R.id.tabs);
		//因为这里是嵌套使用fragment,所以这里不能直接传getActivity().getSupportFragmentManager(),他返回的是父fragment
		//应当使用当前fragment的FragmentManager(),返回当前fragment
		pager.setAdapter(new PagerAdapter(this.getChildFragmentManager()));
		tabs.setViewPager(pager);
		InitTabsConfig();
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		return inflater.inflate(R.layout.fragment_index, container, false);
	}
	
	private void InitTabsConfig() {
		// 设置Tab是自动填充满屏幕的
		tabs.setShouldExpand(true);
		// 设置Tab的分割线是透明的
		tabs.setDividerColor(Color.TRANSPARENT);
		// 设置Tab底部线的高度
		tabs.setUnderlineHeight((int) TypedValue.applyDimension(
				TypedValue.COMPLEX_UNIT_DIP, 1, dm));
		// 设置Tab Indicator的高度
		tabs.setIndicatorHeight((int) TypedValue.applyDimension(
				TypedValue.COMPLEX_UNIT_DIP, 2, dm));
		// 设置Tab标题文字的大小
		tabs.setTextSize((int) TypedValue.applyDimension(
				TypedValue.COMPLEX_UNIT_SP, 16, dm));
		// 设置Tab Indicator的颜色
		tabs.setIndicatorColor(getResources().getColor(R.color.red));
		// 设置选中Tab文字的颜色
		tabs.setSelectedTextColor(getResources().getColor(R.color.red));
		// 取消点击Tab时的背景色
		tabs.setTabBackground(0);
	}

	/**
	 * 此处应当继承FragmentStatePagerAdapter
	 * 在处理数据量较大的页面应当使用FragmentStatePagerAdapter,而不是FragmentPagerAdapter
	 */
	public class PagerAdapter extends FragmentStatePagerAdapter {
		public PagerAdapter(FragmentManager fm) {
			super(fm);
		}

		@Override
		public CharSequence getPageTitle(int position) {
			return titles[position];
		}

		@Override
		public int getCount() {
			return titles.length;
		}
		
		@Override  
		public Fragment getItem(int position) {
			switch (position) {
				case 0:
					fragment = new GoodsFargment();
					break;
				case 1:
					fragment = new ShopingsFragment();
					break;
				case 2:
					fragment = new MatchFragment();
					break;
				default:
					break;
			}
			return fragment;
		}

	}

}

注意到代码,这里使用this.getChildFragmentManager()来表示当前的Fragment为子Fragment,不能使用getActivity().getSupportFragmentManager(),否则在切换时候会出错,第二个地方为第X行,这里继承的是 FragmentStatePagerAdapte,而非FragmentPagerAdapter。

 (2)图片轮播

  我们知道OnTouch事件的响应机制是逐级响应的,他会自动响应最底层的View,因此考虑到图片轮播需要左右滑动,而PageTabs也会左右滑动,并且PageTabs在图片轮转View的下一层,如果使用原生控件,系统会优先响应PageTabs而不会响应ViewPage的图片滑动;因此需要考虑,重写ViewPager控件,让该控件只会响应自己的左右滑动事件,其父视图的View左右滑动事件不响应。

public class ChildViewPager extends ViewPager {
	public ChildViewPager(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	public ChildViewPager(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent arg0) {
		// 当拦截触摸事件到达此位置的时候,返回true,
		// 说明将onTouch拦截在此控件,进而执行此控件的onTouchEvent
		return true;
	}


	@Override
	public boolean onTouchEvent(MotionEvent arg0) {
		getParent().requestDisallowInterceptTouchEvent(true);
		return super.onTouchEvent(arg0);
	}
}
 代码很少,主要是这一句getParent().requestDisallowInterceptTouchEvent( true);

设置父控件不响应OnTouch事件,而是交给当前控件的onTouchEvent事件,从而阻止PageTabS的滑动,响应当前控件的滑动事件

最后这是ViewPage的数据适配器,添加图片和点,进行左右的移动,定义ImgaePagerAdapter适配器类,其代码如下:

public class ImgaePagerAdapter extends PagerAdapter {

	ImageView[] mImageViews;

	public ImgaePagerAdapter(ImageView[] mImageViews) {
		this.mImageViews = mImageViews;
	}
	//获取要滑动的控件的数量
	@Override
	public int getCount() {
		return Integer.MAX_VALUE;
	}
	//来判断显示的是否是同一张图片,这里我们将两个参数相比较返回即可  
	@Override
	public boolean isViewFromObject(View arg0, Object arg1) {
		return arg0 == arg1;
	}
	//PagerAdapter如果滑动的图片超出了缓存的范围,就会调用这个方法,将图片销毁  
	@Override
	public void destroyItem(View container, int position, Object object) {
		
		((ViewPager) container).removeView(mImageViews[position
				% mImageViews.length]);

	}

	/**
	 *循环读取图片,取余数
	 */
	@Override
	public Object instantiateItem(View container, int position) {
		((ViewPager) container).addView(mImageViews[position
				% mImageViews.length], 0);
		return mImageViews[position % mImageViews.length];
	}

}
循环图片的代码主要放在了instantiateItem中,该事件负责将图片添加到容器中,并返回该图片视图,并且每次返回的图片为当前的位置和图片的总长度取余数,通过取余数从而判断是否进行循环。

在Fragment中调用如下的代码对数据适配器的绑定

viewPager.setAdapter(new ImgaePagerAdapter(mImageViews));

viewPager.setOnPageChangeListener(this);

(3)控件

这里的列表控件用来显示精选衣服基本信息,使用图片加文字的组合方式,我们第一反应想到的是GridView控件,这个想法是对的;可是我们注意到“精选”菜单的整个布局是使用ScrollView控件来控制上下一起移动的,如果单纯使用GridView控件的话,GridView控件在ScrollView中会显示不正常,所以我们应当自定义GirdView让它不能滑动,并且适配ScrollView控件的大小。定义MyGridView控件:

public class ImgaePagerAdapter extends PagerAdapter {

	ImageView[] mImageViews;

	public ImgaePagerAdapter(ImageView[] mImageViews) {
		this.mImageViews = mImageViews;
	}
	//获取要滑动的控件的数量
	@Override
	public int getCount() {
		return Integer.MAX_VALUE;
	}
	//来判断显示的是否是同一张图片,这里我们将两个参数相比较返回即可  
	@Override
	public boolean isViewFromObject(View arg0, Object arg1) {
		return arg0 == arg1;
	}
	//PagerAdapter如果滑动的图片超出了缓存的范围,就会调用这个方法,将图片销毁  
	@Override
	public void destroyItem(View container, int position, Object object) {
		
		((ViewPager) container).removeView(mImageViews[position
				% mImageViews.length]);

	}

	/**
	 *循环读取图片,取余数
	 */
	@Override
	public Object instantiateItem(View container, int position) {
		((ViewPager) container).addView(mImageViews[position
				% mImageViews.length], 0);
		return mImageViews[position % mImageViews.length];
	}

}
在绘制GridView控件大小的时候,通过设置MeasureSpec.AT_MOST参数来指定到想要控件高度,通过onMeasure事件来绘制GridView。在XML布局中引用<com.blog.mogujie.tool.MyGridView ../>,布局文件代码太长就不贴出来了,待会在后面提供代码下载链接。

然后再定义该GridView文件的适配器,代码如下,注意GridView的优化设置:

public class GrdoneAdapter extends BaseAdapter{

	private Context mContext;
	private List<GrdOneInfo> mGrdOneInfoList;
	public GrdoneAdapter(Context mContext,List<GrdOneInfo> mGrdOneInfoList){
		this.mContext=mContext;
		this.mGrdOneInfoList=mGrdOneInfoList;
	}
	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return mGrdOneInfoList.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View view = convertView;
		final ViewHolder holder;
		if (convertView == null) {
			view = ((Activity) mContext).getLayoutInflater().inflate(
					R.layout.item_grd1, parent, false);
			holder = new ViewHolder();
			holder.image = (ImageView) view.findViewById(R.id.grdimage);
			holder.brife= (TextView) view.findViewById(R.id.brife1);
			holder.price= (TextView) view.findViewById(R.id.price);
			holder.marks= (TextView) view.findViewById(R.id.marks);
			view.setTag(holder);
		} else {
			holder = (ViewHolder) view.getTag();
		}
		holder.image.setImageResource(mGrdOneInfoList.get(position).imagePath);
		if(mGrdOneInfoList.get(position).brife.length()>50){
			holder.brife.setText(mGrdOneInfoList.get(position).brife.subSequence(0, 30)+"...");
		}else{
			holder.brife.setText(mGrdOneInfoList.get(position).brife);
		}
		holder.price.setText(mGrdOneInfoList.get(position).price);
		holder.marks.setText(mGrdOneInfoList.get(position).marksNum);
		return view;
	}

	static class ViewHolder{
		ImageView image;
		TextView brife;
		TextView price;
		TextView marks;
	}
}
最终效果如下:

 


资源地址为点击打开链接,今天到这里。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值