码迷,mamicode.com
首页 > 微信 > 详细

微信底部导航渐变效果-----viewpager&PorterDuffXfermode

时间:2015-03-09 01:47:03      阅读:533      评论:0      收藏:0      [点我收藏+]

标签:android   开源项目   源码   

实现这个功能主要涉及的知识点有

  1. ViewPager
  2. PorterDuffXfermode
  3. 自定义视图

ViewPager

关于ViewPager需要注意的知识主要是OnPageChangeListener,该接口的三个方法如下
public abstract void onPageScrollStateChanged (int state)

public abstract void onPageScrolled (int position, float positionOffset, int positionOffsetPixels)

public abstract void onPageSelected (int position)


第一个方法onPageScrollStateChanged 中的参数state,有三个可取的值
public static final int SCROLL_STATE_DRAGGING
Constant Value: 1 (0x00000001)

public static final int SCROLL_STATE_IDLE
Constant Value: 0 (0x00000000)

public static final int SCROLL_STATE_SETTLING
Constant Value: 2 (0x00000002)

SCROLL_STATE_DRAGGING:手指按在viewpager上滑动时
SCROLL_STATE_SETTLING:手指松开后,viewpager自动滑动期间
SCROLL_STATE_IDLE:viewpager滑动进入了某个page。
如果你在onPageScrollStateChanged 中输出state的值,你会发现每次都是按顺序打印出“1---2----0”


第二个方法onPageScrolled的三个参数
position:滑动时,屏幕左侧显示的第一个page
positionOffset:滑动比例,值的范围为[0, 1),手指往左滑动,该值递增,反之递减
positionOffsetPixels:滑动距离,和屏幕有关,手指往左滑动,该值递增,反之递减

我们经常需要检查viewpager的滑动方向并作出一些操作,这时你只需要通过position和positionOffset两个值即可实现该功能。


第三个方法onPageSelected的三个参数
position:当前选择的page序号
该方法被调用的时间比较特别,在上面的第一个方法中的“1---2----0”中的2执行之后,onPageSelected就执行,然后执行“1---2----0”中的0。就是手指松开屏幕之后,onPageSelected被执行。

以下在代码中自己重写的一个OnPageChangeListener
/**
 * @author Quinn
 * @date 2015-2-28
 */
public class MainPagerChangeListener implements OnPageChangeListener{

	public interface PagerCallback{
		public void changePageColor(int index, int offset);
	}
	
	private PagerCallback callback;
	
	public MainPagerChangeListener(MainActivity mainActivity){
		this.callback  = (PagerCallback)mainActivity;
	}
	
	//顺序为1-2-0
	@Override
	public void onPageScrollStateChanged(int state) {
		
	}

	@Override
	public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
		if(positionOffset != 0.0f){
			callback.changePageColor(position+1,  (int)(positionOffset * 255));
			callback.changePageColor(position,  (int)((1-positionOffset) * 255));
		}
	}

	@Override
	public void onPageSelected(int position) {

	}
}

首先我们留一个回调接口PagerCallback,然后在onPageScrolled中执行操作。可以根据position和positionOffset两个值,对两个方向的page进行不同的操作。我们这里进行的操作是改变图标的颜色。

PorterDuffXfermode

先看以下这幅图

技术分享

微信的底部图案,其原型是一个灰色的图案,在滑动时,会发生颜色渐变,那么怎样使一张图片产生这样的效果呢?其原理是利用PorterDuffXfermode!先看以下这张图片

技术分享
上述16个图,我们看第二排的第三个,黄色部分代表Dst,蓝色部分代表Src,将Dst覆盖在Src之上,选择"DstIn"模式,就可以合成上述第二排第三张图片。那么,如果Src是一个灰色的图片(图片部分是透明的,像上面微信的四个图标),Dst是一个绿色的矩形,其大小和图片一致。然后将绿色的矩形覆盖在图片之上,选择“DstIn”模式,就能达到将图片设置成绿色的效果。在这个基础上,要对图片进行颜色渐变,只需在viewpager滑动时修改上述Dst矩形的颜色透明度即可。实现代码可以在文章末尾下载源码。博客主要记录实现思路和细节,贴出代码感觉太冗长了。

自定义视图

自定义视图,一般按以下步骤进行
  • 自定义属性
  • 获取属性
  • 重写onMeasure
  • 重写onDraw
我们在自定义底部带文字的图标,自定义属性如下:

路径:XMPP\res\values\attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="FooterTextIcon">
        <attr name="iconSrc" format="reference" />
        <attr name="color" format="color"/>
        <attr name="text" format="string"/>
        <attr name="textSize" format="dimension"/>
    </declare-styleable>

</resources>

这些自定义属性的使用方式如下
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:FooterIcon="http://schemas.android.com/apk/res/com.quinn.xmpp"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.quinn.xmpp.ui.main.MainActivity" >
//省略,,,,
//,,,
//,,,
 <com.quinn.xmpp.ui.widget.FooterTextIcon
            android:id="@+id/chattingIcon"
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:layout_weight="1"
            FooterIcon:iconSrc="@drawable/ic_action_chat"
            FooterIcon:text="聊天"
            FooterIcon:textSize="12sp"
            android:padding="5dip"
            FooterIcon:color="#ff181818" />
//省略,,,,
//,,,
//,,,
</LinearLayout>

在使用自定义属性时,需要在使用这些自定义属性的布局文件中引入一个命名空间,比如上述代码的第三行,它的格式是:
xmlns:自己起一个名字="http://schemas.android.com/apk/res/应用的包名"
注意,上面代码的最后一部分是应用的包名,而不是某个Activity的包名或者自定义组件对应Java文件的包名

前面自定义属性的attrs.xml中,可以自定义的属性类型(对应上述的format)有以下几种
reference、string、color、dimension、boolean、integer、float、fraction、enum、flag
主要讲讲其中比较常用而且容易混淆的四个
reference的值必须是"@drawable/xxxxxx"
比如上面的
FooterIcon:iconSrc="@drawable/ic_action_chat"
而string,color,dimension的值可以直接写某个值,也可以是引用于资源文件string.xml,color.xml,dimens.xml
比如
            FooterIcon:text="聊天"
            FooterIcon:textSize="12sp"
            android:padding="5dip"
            FooterIcon:color="#ff181818"</span>
也可以写成
            FooterIcon:text="@string/xxxxx"
            FooterIcon:textSize="@dimen/xxxx"
            android:padding="@dimen/xxxx"
            FooterIcon:color="@color/xxxx" />
然后,我们需要在一个地方使用这些属性的值,就是在我们的自定义组件的类文件中。如下:
public class FooterTextIcon extends View {


	//四个属性
	private String text;
	private int themeColor;
	private int textSize;
	private int iconRid;
	//、、、


	/**
	 * @param context
	 */
	public FooterTextIcon(Context context) {
		this(context, null);
	}

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

	/**
	 * @param context
	 * @param attrs
	 * @param defStyleAttr
	 */
	public FooterTextIcon(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.FooterTextIcon);
		iconRid = a.getResourceId(R.styleable.FooterTextIcon_iconSrc, -1);
		text = a.getString(R.styleable.FooterTextIcon_text);
		textSize = (int) a.getDimension(R.styleable.FooterTextIcon_textSize, TypedValue
				.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12,
						getResources().getDisplayMetrics()));
		themeColor = a.getColor(R.styleable.FooterTextIcon_color, Color.parseColor(DEFAULT_CHOSEN_COLOR));
		a.recycle();
                //,,,
		
	}
        //,,省略,,

}
如上,我们在构造函数中,通过一个TypeArray对象获取各种类型的属性,并且最后调用TypeArray的recycle函数回收内存。一般我们将这些代码放在有三个参数的构造方法中执行,而又一个参数的构造方法直接用this指针调用有两个参数的构造方法,同理,两个的调用三个的。


关于自定义组件的知识可以参考另外两篇博客


该功能目前应用于我的XMPP项目  https://github.com/Leaking/xmppIM

后续坚持把写这个开源项目使用到的知识都记录在博客里。






微信底部导航渐变效果-----viewpager&PorterDuffXfermode

标签:android   开源项目   源码   

原文地址:http://blog.csdn.net/chziroy/article/details/44087995

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!