android 打造炫酷导航栏(仿UC头条)

年后开始上班甚是清闲,所以想捣鼓一些东西。在翻阅大神杰作Android 教你打造炫酷的ViewPagerIndicator 不仅仅是高仿MIUI 的时候看到下面有一条评论说,如果导航栏能滑动就更好了。我就想我可以去改一下就可以。然后又想感觉有点像UC的头条的界面。于是就往里面加东西,调试写代码。弄了两天有点效果了,写出来看看了。

项目下载地址:http://download.csdn.net/detail/qq_16064871/9434291

1、先看效果

用咔咔大师录屏的gif效果,有点失真。



这是第一个版本的效果。因为我不断往里面加东西,所以有几个版本了。

2、这个版本基本代码

实现思路就是自定义绘制了。主要有两层,第一层是ViewPagerIndicator。主要负责导航栏的三角形指示器的绘制,以及页面滑动的回调,控制。当然这里需要android.support.v4.view.ViewPager这东西配合使用。

第二层是,导航栏的滑动效果,以及最左、最右有 反弹的效果。这个效果我是从以前一篇博文改动到了这里来。链接:android 滚动条下拉反弹的效果(类似微信朋友圈)。这里效果是垂直,改为横向就行了。还有这两层同时使用需要处理就是滑动不要冲突就可以了。

xml布局代码:

        <com.ucnew.view.BounceScrollView
            android:id="@+id/id_scrollview"
            android:layout_width="0dp"
            android:layout_height="45dp"
            android:layout_weight="1"
            android:focusableInTouchMode="false"
            android:scrollbars="none" >

            <com.ucnew.view.ViewPagerIndicator
                android:id="@+id/id_indicator"
                android:layout_width="match_parent"
                android:layout_height="45dp"
                android:orientation="horizontal"
                mmsx:item_count="4" >
            </com.ucnew.view.ViewPagerIndicator>
        </com.ucnew.view.BounceScrollView>

3、自定义view的java代码

ViewPagerIndicator

package com.ucnew.view;

import java.util.List;

import com.ucnew.activity.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;

public class ViewPagerIndicator extends LinearLayout
{
	//绘制三角形的画笔
	private Paint mPaint;
	 //path构成一个三角形
	private Path mPath;
	//三角形的宽度
	private int mTriangleWidth;
	// 三角形的高度
	private int mTriangleHeight;
	 //三角形的宽度为单个Tab的1/6
	private static final float RADIO_TRIANGEL = 1.0f / 6;
	// 三角形的最大宽度
	private final int DIMENSION_TRIANGEL_WIDTH = (int) (getScreenWidth() / 3 * RADIO_TRIANGEL);
	//初始时,三角形指示器的偏移量
	private int mInitTranslationX;
	 // 手指滑动时的偏移量
	private float mTranslationX;
	 // tab数量
	private int mTabVisibleCount;
	 // tab上的内容
	private List<String> mTabTitles;
	 // 与之绑定的ViewPager
	public ViewPager mViewPager;
	 // 标题正常时的颜色
	private static final int COLOR_TEXT_NORMAL = 0x77FFFFFF;
	 //标题选中时的颜色
	private static final int COLOR_TEXT_HIGHLIGHTCOLOR = 0xFFFFFFFF;
	
	public ViewPagerIndicator(Context context)
	{
		this(context, null);
	}

	public ViewPagerIndicator(Context context, AttributeSet attrs)
	{
		super(context, attrs);

		// 获得自定义属性,tab的数量
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.ViewPagerIndicator);
		mTabVisibleCount = a.getInt(R.styleable.ViewPagerIndicator_item_count,4);
		if (mTabVisibleCount < 0)
			mTabVisibleCount = 4;
		a.recycle();

		// 初始化画笔
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
		mPaint.setColor(Color.parseColor("#ffffffff"));
		mPaint.setStyle(Style.FILL);
		mPaint.setPathEffect(new CornerPathEffect(3));

	}

	//绘制指示器
	@Override
	protected void dispatchDraw(Canvas canvas)
	{
		canvas.save();
		// 画笔平移到正确的位置
		canvas.translate(mInitTranslationX + mTranslationX, getHeight() + 1);
		canvas.drawPath(mPath, mPaint);
		canvas.restore();

		super.dispatchDraw(canvas);
	}

	 //初始化三角形的宽度
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh)
	{
		super.onSizeChanged(w, h, oldw, oldh);
		mTriangleWidth = (int) (w / mTabVisibleCount * RADIO_TRIANGEL);// 1/6 of
																		// width
		mTriangleWidth = Math.min(DIMENSION_TRIANGEL_WIDTH, mTriangleWidth);

		// 初始化三角形
		initTriangle();

		// 初始时的偏移量
		mInitTranslationX = getScreenWidth() / mTabVisibleCount / 2 - mTriangleWidth / 2;
	}

	 //设置可见的tab的数量
	public void setVisibleTabCount(int count)
	{
		this.mTabVisibleCount = count;
	}

    //设置tab的标题内容 可选,生成textview加入布局,灵活处理
	public void setTabItemTitles(List<String> datas)
	{
		// 如果传入的list有值,则移除布局文件中设置的view
		if (datas != null && datas.size() > 0)
		{
			this.removeAllViews();
			this.mTabTitles = datas;

			for (String title : mTabTitles)
			{
				// 添加view
				addView(generateTextView(title));
			}
			// 设置item的click事件
			setItemClickEvent();
		}

	}
	
	//根据标题生成我们的TextView
	private TextView generateTextView(String text)
	{
		TextView tv = new TextView(getContext());
		LinearLayout.LayoutParams lp = new LayoutParams(
				LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
		lp.width = getScreenWidth() / mTabVisibleCount;
		tv.setGravity(Gravity.CENTER);
		tv.setTextColor(COLOR_TEXT_NORMAL);
		tv.setText(text);
		tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
		tv.setLayoutParams(lp);
		return tv;
	}

	//对外的ViewPager的回调接口
	public interface PageChangeListener
	{
		public void onPageScrolled(int position, float positionOffset,
				int positionOffsetPixels);

		public void onPageSelected(int position);

		public void onPageScrollStateChanged(int state);
	}

	// 对外的ViewPager的回调接口
	private PageChangeListener onPageChangeListener;

	// 对外的ViewPager的回调接口的设置
	public void setOnPageChangeListener(PageChangeListener pageChangeListener)
	{
		this.onPageChangeListener = pageChangeListener;
	}

	// 设置关联的ViewPager,以及传入 BounceScrollView,进行设置滚动
	public void setViewPager(ViewPager mViewPager, final BounceScrollView scrollView, int pos)
	{
		this.mViewPager = mViewPager;
		
		mViewPager.setOnPageChangeListener(new OnPageChangeListener()
		{
			@Override
			public void onPageSelected(int position)
			{
				// 设置字体颜色高亮
				resetTextViewColor();
				highLightTextView(position);

				// 回调
				if (onPageChangeListener != null)
				{
					onPageChangeListener.onPageSelected(position);
				}
			}

			@Override
			public void onPageScrolled(int position, float positionOffset,
					int positionOffsetPixels)
			{
				// 滚动
				scroll(scrollView,position, positionOffset);
				// 回调
				if (onPageChangeListener != null)
				{
					onPageChangeListener.onPageScrolled(position,
							positionOffset, positionOffsetPixels);
				}
			}

			@Override
			public void onPageScrollStateChanged(int state)
			{
				// 回调
				if (onPageChangeListener != null)
				{
					onPageChangeListener.onPageScrollStateChanged(state);
				}

			}
		});
		// 设置当前页
		mViewPager.setCurrentItem(pos);
		// 高亮
		highLightTextView(pos);
	}

	//高亮文本
	protected void highLightTextView(int position)
	{
		View view = getChildAt(position);
		if (view instanceof TextView)
		{
			((TextView) view).setTextColor(COLOR_TEXT_HIGHLIGHTCOLOR);
		}

	}

	//重置文本颜色
	private void resetTextViewColor()
	{
		for (int i = 0; i < getChildCount(); i++)
		{
			View view = getChildAt(i);
			if (view instanceof TextView)
			{
				((TextView) view).setTextColor(COLOR_TEXT_NORMAL);
			}
		}
	}

	// 设置点击事件
	public void setItemClickEvent()
	{
		int cCount = getChildCount();
		for (int i = 0; i < cCount; i++)
		{
			final int j = i;
			View view = getChildAt(i);
			view.setOnClickListener(new OnClickListener()
			{
				@Override
				public void onClick(View v)
				{
					mViewPager.setCurrentItem(j);
				}
			});
		}
	}

	// 初始化三角形指示器
	private void initTriangle()
	{
		mPath = new Path();

		mTriangleHeight = (int) (mTriangleWidth / 2 / Math.sqrt(2));
		mPath.moveTo(0, 0);
		mPath.lineTo(mTriangleWidth, 0);
		mPath.lineTo(mTriangleWidth / 2, -mTriangleHeight);
		mPath.close();
	}
	
	//指示器跟随手指滚动,以及容器滚动
	public void scroll(BounceScrollView scrollView,int position, float offset)
	{
		// 不断改变偏移量,invalidate
		mTranslationX = getScreenWidth() / mTabVisibleCount * (position + offset);

		int tabWidth = getScreenWidth() / mTabVisibleCount;

		// 容器滚动,当移动到倒数最后一个的时候,开始滚动
		if (offset > 0 && position >= (mTabVisibleCount - 1) && getChildCount() > mTabVisibleCount)
		{
			
			if (mTabVisibleCount != 1)
			{
				//下面注释掉,是滚动ViewPagerIndicator这个LinearLayout
//				this.scrollTo((position - (mTabVisibleCount - 1)) * tabWidth + (int) (tabWidth * offset), 0);
				//只滚动滚动条,禁止滚动lineayout
				scrollView.setScrolledTo((position - (mTabVisibleCount - 1)) * tabWidth + (int) (tabWidth * offset), 0);
			} else
			// 为count为1时 的特殊处理
			{
				this.scrollTo(position * tabWidth + (int) (tabWidth * offset), 0);
//				scrollView.setScrolledTo(position * tabWidth + (int) (tabWidth * offset), 0);
			}
		}
		//处理特殊情况
		else if (offset > 0 && position <= mTabVisibleCount - 1) {
			scrollView.setScrolledTo(0, 0);
		}

		invalidate();
	}

	//设置布局中view的一些必要属性;如果设置了setTabTitles,布局中view则无效
	@Override
	protected void onFinishInflate()
	{
		super.onFinishInflate();

		int cCount = getChildCount();

		if (cCount == 0)
			return;

		for (int i = 0; i < cCount; i++)
		{
			View view = getChildAt(i);
			LinearLayout.LayoutParams lp = (LayoutParams) view
					.getLayoutParams();
			lp.weight = 0;
			lp.width = getScreenWidth() / mTabVisibleCount;
			view.setLayoutParams(lp);
		}
		// 设置点击事件
		setItemClickEvent();

	}

	//获得屏幕的宽度
	public int getScreenWidth()
	{
		WindowManager wm = (WindowManager) getContext().getSystemService(
				Context.WINDOW_SERVICE);
		DisplayMetrics outMetrics = new DisplayMetrics();
		wm.getDefaultDisplay().getMetrics(outMetrics);
		return outMetrics.widthPixels ;
	}

}

BounceScrollView

package com.ucnew.view;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.TranslateAnimation;
import android.widget.HorizontalScrollView;

/**
 * ScrollView反弹效果的实现
 */
public class BounceScrollView extends HorizontalScrollView {
	// 孩子View
	private View inner;
    // 点击时x坐标
	private float x;
	// 矩形(这里只是个形式,只是用于判断是否需要动画
	private Rect normal = new Rect();
    // 是否开始计算
	private boolean isCount = false;
	private RotatImageView  mRotatImageView;
	
	public BounceScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}
	
	/***
	 * 根据 XML 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onFinishInflate
	 * 方法,也应该调用父类的方法,使该方法得以执行.
	 */
	@Override
	protected void onFinishInflate() {
		if (getChildCount() > 0) {
			inner = getChildAt(0);
		}
	}
	
	//手动需要设置滚动位置
	public void setScrolledTo(int position, float positionOffset) {
		this.scrollTo(position,(int) positionOffset);
	}

	 //监听touch
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		if (inner != null) {
			commOnTouchEvent(ev);
		}

		return super.onTouchEvent(ev);
	}

	//触摸事件
	public void commOnTouchEvent(MotionEvent ev) {
		int action = ev.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			break;
		case MotionEvent.ACTION_UP:
			// 手指松开.
			if (isNeedAnimation()) {
				animation();
				isCount = false;
			}
			break;
		/***
		 * 排除出第一次移动计算,因为第一次无法得知y坐标, 在MotionEvent.ACTION_DOWN中获取不到,
		 * 因为此时是MyScrollView的touch事件传递到到了LIstView的孩子item上面.所以从第二次计算开始.
		 * 然而我们也要进行初始化,就是第一次移动的时候让滑动距离归0. 之后记录准确了就正常执行.
		 */
		case MotionEvent.ACTION_MOVE:
			final float preX = x;// 按下时的y坐标
			float nowX = ev.getX();// 时时y坐标
			int deltaX = (int) (preX - nowX);// 滑动距离
			if (!isCount) {
				deltaX = 0; // 在这里要归0.
			}

			x = nowX;
			// 当滚动到最上或者最下时就不会再滚动,这时移动布局
			if (isNeedMove()) {
				// 初始化头部矩形
				if (normal.isEmpty()) {
					// 保存正常的布局位置
					normal.set(inner.getLeft(), inner.getTop(),
							inner.getRight(), inner.getBottom());
				}
				// 移动布局
				inner.layout(inner.getLeft() - deltaX / 4, inner.getTop(),
						inner.getRight()  - deltaX / 4, inner.getBottom());
				
				//图片加号旋转,如果不需要这个直接删了就行
				if (mRotatImageView != null) {
					mRotatImageView.setRotationLeft();
				}
			}
			isCount = true;
			break;

		default:
			break;
		}
	}

	//回缩动画
	public void animation() {
		// 开启移动动画
		TranslateAnimation ta = new TranslateAnimation(0, 0, inner.getTop(),
				normal.top);
		ta.setDuration(200);
		inner.startAnimation(ta);
		// 设置回到正常的布局位置
		inner.layout(normal.left, normal.top, normal.right, normal.bottom);
		normal.setEmpty();

	}
	
	//设置图片加号旋转
	public void setRotatImageView(RotatImageView rotatImageView){
		this.mRotatImageView = rotatImageView;
	}

	// 是否需要开启动画
	public boolean isNeedAnimation() {
		return !normal.isEmpty();
	}

	/***
	 * 是否需要移动布局 inner.getMeasuredHeight():获取的是控件的总高度
	 * getHeight():获取的是屏幕的高度
	 */
	public boolean isNeedMove() {
		int offset = inner.getMeasuredWidth() - getWidth();
		int scrollX = getScrollX();
		
		// 0是顶部反弹
		//是底部反弹加上    
		if (scrollX == 0  || scrollX == offset) {
			return true;
		}
		return false;
	}

}

都有很详细的注释,以及测试需要说明。

那么就直接看下一个版本。

4、看下一个版本效果


多了一个图标,这个图标可以用来监听,等等。

我后面捣鼓加了一个旋转动画,动画效果可能不是很好。但也可以看看。

5、xml代码

有一些自定义属性以及效果的代码就不贴,感兴趣下载源码。看不懂的,看我前几篇文章,自定义控件使用。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:mmsx="http://schemas.android.com/apk/res/com.ucnew.activity"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffffff"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#8000bf5f" >

        <com.ucnew.view.BounceScrollView
            android:id="@+id/id_scrollview"
            android:layout_width="0dp"
            android:layout_height="45dp"
            android:layout_weight="1"
            android:focusableInTouchMode="false"
            android:scrollbars="none" >

            <com.ucnew.view.ViewPagerIndicator
                android:id="@+id/id_indicator"
                android:layout_width="match_parent"
                android:layout_height="45dp"
                android:orientation="horizontal"
                mmsx:item_count="4" >
            </com.ucnew.view.ViewPagerIndicator>
        </com.ucnew.view.BounceScrollView>

        <com.ucnew.view.RotatImageView
            android:id="@+id/id_rotat_imageView"
            android:layout_width="50dp"
            android:layout_height="wrap_content"
            android:paddingLeft="30dp"
            android:layout_gravity="center"
            mmsx:src="@drawable/add" >
        </com.ucnew.view.RotatImageView>
    </LinearLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/id_vp"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" >
    </android.support.v4.view.ViewPager>

</LinearLayout>

6、增加以及这里主要主要需要改的代码。

ViewPagerIndicator类的这个函数

	//获得屏幕的宽度
	public int getScreenWidth()
	{
		WindowManager wm = (WindowManager) getContext().getSystemService(
				Context.WINDOW_SERVICE);
		DisplayMetrics outMetrics = new DisplayMetrics();
		wm.getDefaultDisplay().getMetrics(outMetrics);
		//获取是整个屏幕的宽度,我试过自定义宽度测量宽度,不行。因为本身还没内容,是后面添加的。所以需要后面加东西
		//需要这里减去宽度就行。其中这里减去120就是60dp的宽度
		return outMetrics.widthPixels -100;
	}

还有一个图片的旋转类RotatImageView

package com.ucnew.view;

import com.ucnew.activity.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class RotatImageView extends View {
	private Paint paint = null; // 画笔
	private Bitmap mbitmap = null; // 图片位图
	private Bitmap bitmapDisplay = null;
	private Matrix matrix = null;
	private int mWidth = 0; // 图片的宽度
	private int mHeight = 0; // 图片的高度
	private float fAngle = 180.0f; // 图片旋转
	private PaintFlagsDrawFilter mDrawFilter; 

	public RotatImageView(Context context) {
		super(context);
	}
	
	public RotatImageView(Context context, AttributeSet attrs)
	{
		this(context, attrs, 0);
	}

	/**
	 * 初始化一些自定义的参数
	 * 
	 * @param context
	 * @param attrs
	 * @param defStyle
	 */
	public RotatImageView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);

		TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
				R.styleable.RotatImageView, defStyle, 0);

		int n = a.getIndexCount();
		for (int i = 0; i < n; i++) {
			int attr = a.getIndex(i);
			switch (attr) {
			// 原始图片,在布局里面获取
			case R.styleable.RotatImageView_src:
				mbitmap = BitmapFactory.decodeResource(getResources(),a.getResourceId(attr, 0));
				bitmapDisplay = mbitmap;
				break;
			}
		}
		a.recycle();

        mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);
		paint = new Paint();
		paint.setFlags(Paint.ANTI_ALIAS_FLAG);

		matrix = new Matrix();
	}
	
	/**
	 * 计算控件的高度和宽度
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
	{
		// 设置宽度
		int specMode = MeasureSpec.getMode(widthMeasureSpec);
		int specSize = MeasureSpec.getSize(widthMeasureSpec);

		//match_parent或者设置的精确值获取
		//MeasureSpec.EXACTLY
		if (specMode == MeasureSpec.EXACTLY)
		{
			mWidth = specSize;
		} 
		else
		{
			// 由图片决定的宽
			//getPaddingLeft(),getPaddingRight()这两个值是控件属性的向内偏移的距离值,所以的一起计算
			//区别于layout_marginLeft,两个控件的左间距值设置
			int desireByImg = getPaddingLeft() + getPaddingRight()
					+ mbitmap.getWidth();
			
			// wrap_content
			if (specMode == MeasureSpec.AT_MOST)
			{
				//所以最小的值,宽度的话是左右内偏移距离之和
				mWidth = Math.min(desireByImg, specSize);
			} else

				mWidth = desireByImg;
		}

		// 设置高度,部分解释同上
		specMode = MeasureSpec.getMode(heightMeasureSpec);
		specSize = MeasureSpec.getSize(heightMeasureSpec);
		
		//match_parent或者设置的精确值获取
		//MeasureSpec.EXACTLY
		if (specMode == MeasureSpec.EXACTLY)
		{
			mHeight = specSize;
		} else
		{
			int desire = getPaddingTop() + getPaddingBottom()
					+ mbitmap.getHeight();

			// wrap_content
			if (specMode == MeasureSpec.AT_MOST)
			{
				mHeight = Math.min(desire, specSize);
			} else
				mHeight = desire;
		}

		//计算好的宽度以及高度是值,设置进去
		setMeasuredDimension(mWidth, mHeight);
	}

	// 向左旋转
	public void setRotationLeft() {
		fAngle = fAngle - 20;
		setAngle();
	}

	// 向右旋转
	public void setRotationRight() {
		fAngle = fAngle + 20;
		setAngle();
	}
	
	private boolean isRoate = false;
	// 设置旋转比例
	private void setAngle() {
		Log.i("Show", String.valueOf(fAngle));
		isRoate = true;
		//设置图片的旋转中心,即绕(X,Y)这点进行中心旋转 要旋转的角度
		matrix.preRotate(fAngle, (float)mbitmap.getWidth()/2, (float)mbitmap.getHeight()/2); 
		invalidate();
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		
		//消除锯齿, 图片旋转后的锯齿消除不成功,实在不行图片边缘加一些白色像素点
		canvas.setDrawFilter(mDrawFilter); 
		if (isRoate) {
			canvas.drawBitmap(bitmapDisplay, matrix, paint);
			isRoate = false;
		}else {
			canvas.drawBitmap(bitmapDisplay, 0, 0, paint);	
		}
	}
}

activity调用以及初始化这些自定义控件

package com.ucnew.activity;

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

import com.ucnew.activity.R;
import com.ucnew.fragment.VpSimpleFragment;
import com.ucnew.view.BounceScrollView;
import com.ucnew.view.RotatImageView;
import com.ucnew.view.ViewPagerIndicator;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.Window;

public class MainActivity extends FragmentActivity
{
	private List<Fragment> mTabContents = new ArrayList<Fragment>();
	private FragmentPagerAdapter mAdapter;
	private ViewPager mViewPager;
	private List<String> mDatas = Arrays.asList("页面1", "页面2", "页面3", "页面4",
			"页面5", "页面6", "页面7", "页面8", "页面9");

	private ViewPagerIndicator mIndicator;
	private BounceScrollView mScrollView;
	private RotatImageView mRotatImageView;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.vp_indicator);

		initView();
		initDatas();
		//设置Tab上的标题
		mIndicator.setTabItemTitles(mDatas);
		mViewPager.setAdapter(mAdapter);
		//设置关联的ViewPager
		mIndicator.setViewPager(mViewPager,mScrollView,0);
		//设置关联的图片旋转,根据需要设置,效果不是很好
		mScrollView.setRotatImageView(mRotatImageView);
	}

	private void initDatas()
	{

		for (String data : mDatas)
		{
			VpSimpleFragment fragment = VpSimpleFragment.newInstance(data);
			mTabContents.add(fragment);
		}

		mAdapter = new FragmentPagerAdapter(getSupportFragmentManager())
		{
			@Override
			public int getCount()
			{
				return mTabContents.size();
			}

			@Override
			public Fragment getItem(int position)
			{
				return mTabContents.get(position);
			}
		};
	}

	private void initView()
	{
		mScrollView = (BounceScrollView) findViewById(R.id.id_scrollview);
		mViewPager = (ViewPager) findViewById(R.id.id_vp);
		mIndicator = (ViewPagerIndicator) findViewById(R.id.id_indicator);
		mRotatImageView = (RotatImageView)findViewById(R.id.id_rotat_imageView);
		
	}


}

还有部分代码没贴。自已下载查看吧。


7、最后效果图


录屏不是很清晰,来一张截图,够清晰的



项目下载地址:http://download.csdn.net/detail/qq_16064871/9434291

用到知识

Android 教你打造炫酷的ViewPagerIndicator 不仅仅是高仿MIUI

android 滚动条下拉反弹的效果(类似微信朋友圈)

 

android 自定义控件以及自定义view学习(随机验证码生成)


 

android 自定义控件属性(TypedArray以及attrs解释)


 

android 自定义图片合集(自定义控件)


  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值