zoukankan      html  css  js  c++  java
  • 仿蘑菇街界面(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;
    	}
    }
    终于效果例如以下:

     


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

  • 相关阅读:
    下载并使用ASP.NET MVC v1.0 Futures
    关于DataGridView的数据源两个值得注意的小问题
    C++网络编程(二)客户端服务器程序
    C++多态、继承的简单分析
    XML文件解析器TXml
    数组
    CTS类型系统
    光阴不会虚度
    软件的大规模生产
    微创新和山寨的关系
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/6796210.html
Copyright © 2011-2022 走看看