1. 程式人生 > >自定義控制元件--讓背景顏色隨ViewPager的滑動而漸變

自定義控制元件--讓背景顏色隨ViewPager的滑動而漸變

轉載請註明出處,謝謝~

今天要說一個簡單但不好想的效果實現。程式碼絕對簡單,實現絕對easy,就是你可能想不到而已。

不多說,上效果圖。第一個效果是仿最美應用的滑動顏色變化,第二個是我專案中要用的效果,實現後我就貼出來了,開源嘛。

             

下面分別說說這兩個實現的原理和想法。

首先我們看純色的第一張gif,純色的漸變還是容易一些的。

1.實現一個ViewPager,因為我們要實現的是,隨著手指的移動,viewpager的背景色改變,所以暫時的想法是,不需要自定義viewpager。

2.給背景設定一個純色的color。

3.viewpager的滑動,如何獲取,如何處理

4.如何讓顏色漸變,怎麼獲取漸變值

下面我們一個一個的解決。

1.使用viewpager貌似是很簡單的,這裡不復述了,程式碼我貼上:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="20dp"
    android:id="@+id/ll"
    android:orientation="vertical" >

    <TextView
        android:padding="10dp"
        android:layout_width="match_parent"
        android:gravity="center_horizontal"
        android:layout_height="wrap_content"
        android:textColor="#ff000000"
        android:text="這是title" />
    
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </android.support.v4.view.ViewPager>
</LinearLayout>

@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		llLayout = (LinearLayout) findViewById(R.id.ll);
		viewpager = (ViewPager) findViewById(R.id.viewpager);
		fragment = new ImageFragment();
		fragment2 = new ImageFragment();
		fragment3 = new ImageFragment();
		fragment4 = new ImageFragment();
		views.add(fragment2);
		views.add(fragment3);
		views.add(fragment4);
		views.add(fragment);
		viewpager.setAdapter(new MyAdapter(getSupportFragmentManager()));
		viewpager.setCurrentItem(0);
		viewpager.setOnPageChangeListener(new PageChangeLisener());
	}

private class MyAdapter extends FragmentPagerAdapter{

		private List<Fragment> list_views;

		public MyAdapter(FragmentManager fm) {
			super(fm);
			list_views = views;
		}

		@Override
		public Fragment getItem(int arg0) {
			return list_views.get(arg0);
		}

		@Override
		public int getCount() {
			return list_views.size();
		}
		
	}

以上是關於viewpager的一些程式碼,沒有貼全,像是ImageFragment就特別簡單,佈局裡就是一張圖片而已。

下面第二個問題,背景色我們很容易搞定,setBackgroundColor就可以。

然後看第三個問題,並不是所有的滑動處理都要在onTouch裡進行,像viewpager,我們完全可以看它的listener

class PageChangeLisener implements OnPageChangeListener {

		@Override
		public void onPageScrollStateChanged(int arg0) {
		}

		@SuppressLint("NewApi")
		@Override
		public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
			ArgbEvaluator evaluator = new ArgbEvaluator();
			if (position % 2 == 0) {
				llLayout.setBackgroundColor(0XFF8080FF);
				int evaluate = (Integer) evaluator.evaluate(positionOffset, 0XFF8080FF,0XFFFF8080);
				llLayout.setBackgroundColor(evaluate);
			}else {
				llLayout.setBackgroundColor(0XFFFF8080);
				int evaluate = (Integer) evaluator.evaluate(positionOffset, 0XFFFF8080,0XFF8080FF);
				llLayout.setBackgroundColor(evaluate);
			}
		}

		@Override
		public void onPageSelected(int arg0) {
		}
	}

這是整個顏色控制的核心,先說第三個問題,這裡用onPageChangeListener來處理了viewpager的滑動,這裡雖然拿不到座標,但是可以拿到一些對我們來說,很有用的東西,看onPageScrolled方法的第二個引數,這裡做實驗發現,它向右滑動的時候,取值是[0,1),而向左滑動的時候,取值的(1,0],這完全就是為了讓開發者做縮放平移等動畫的小助手啊!

然後,注意了,我們考慮第四個問題,我不知道大家是否熟悉屬性動畫,我首先是在屬性動畫裡寫了一個對backgroundColor屬性設定改變的一個動畫:

@SuppressLint("NewApi")
	private void setBackRepeat(View view,String property,int from , int to){
		ValueAnimator animator = ObjectAnimator.ofInt(view,property,from,to);
		animator.setDuration(2000);
		animator.setRepeatMode(ValueAnimator.REVERSE);
		animator.setRepeatCount(ValueAnimator.INFINITE);
		animator.setEvaluator(new ArgbEvaluator());
		animator.start();
		
		
		animator.addUpdateListener(new AnimatorUpdateListener() {
			
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				// TODO Auto-generated method stub
				System.out.println("value : "+Integer.toHexString((Integer)animation.getAnimatedValue()));
			}
		});
	}

然後我列印了動畫執行時的顏色的變化,然後我發現他居然會漸變成為你想要的顏色,而不是刷的一下就變了,這下,開心了。

把這個屬性動畫裡的顏色估值器拿出來,ArgbEvaluator,就是它!它的實現特別簡單,大家可以點進去看看原始碼,然後用這個估值器我們來做估值。

首先說說這幾個引數,

evaluator.evaluate(positionOffset, 0XFF8080FF,0XFFFF8080);
估值器new出來之後,進行估值,第一個引數是0-1的一個可變引數,0表示開始變化,1表示變化結束,第二個引數是開始的顏色值,第三個引數是結束的顏色值。而這個方法就會一直返回一個在0-1之間過度的顏色值,直到顏色變化完為止。

這樣我們就完全可以試想上述效果了!

接著,我們來實現第二個效果!就是在背景色漸變的基礎上,再加上滑動漸變!

我們仔細看第二個效果,發現viewpager後面的背景色,原本就是從左上角到右下角漸變的,然後滑動過程中,顏色繼續隨手指漸變,滑動結束後,左上角和右下角的顏色互換了位置,中間還是漸變色。是不是比第一個效果瞬間又提升了bigger!我們再來實現一下它!

考慮問題:

1.背景色漸變的實現方式?

2.viewpager是否需要自定義?

3.滑動事件的獲取?

4.漸變的處理?

我們逐個解決。

第一個,背景漸變,大家熟知的shape,對,一開始我也想到了它,而且想到了屬性動畫,對backgroundResource的設定,但是很遺憾,背景色沒有漸變效果,所以放棄。然後背景色的實現,我簡單的自定義了一個view,讓這個view做viewpager的背景,來隨手指漸變。

第二個,viewpager沒有自定義,因為viewpager上沒有特別複雜的效果,沒有特別絢麗的切換(你完全可以自己加上,github有開源的),所以我沒有自定義。

第三個,滑動事件的處理仍然延用了上一個效果的listenr,完全無法捨棄第二個引數offset這個從0-1的小baby啊!

第四個,單純的顏色估值器無法滿足我們的需求,但結合上我們自定義的view就能實現雙漸變效果了!

public class MyLinearLayout extends View {
	
	private LinearGradient gradinet;
	private Paint paint;
	private int width;
	private int height;
	private int start = 0XFFFF8080;
	private int end = 0XFF8080FF;
	
	public MyLinearLayout(Context context) {
		super(context);
		getDisplay(context);
	}

	public MyLinearLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
		getDisplay(context);
	}
	
	private void getDisplay(Context context) {
		WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
		width = wm.getDefaultDisplay().getWidth();
		height = wm.getDefaultDisplay().getHeight();
	}
	
	public void setGradient(int start,int end){
		this.start = start;
		this.end = end;
		gradinet = new LinearGradient(0, 0, width, height, start, end, Shader.TileMode.MIRROR);
		invalidate();
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		System.out.println("!!!!!!!!!!!!!!!!");
		if (paint == null) {
			paint = new Paint();
		}
		if (gradinet == null) {
			gradinet = new LinearGradient(0, 0, width, height, start, end, Shader.TileMode.MIRROR);
		}
		paint.setShader(gradinet);
		canvas.drawRect(0, 0, width	, height, paint);
	}

}

核心!!就是這麼個簡單但重要的自定義控制元件,裡面用LinearGradient實現了漸變,在加上估值器,一個雙漸變效果就這麼出來了!

開源!!這個專案的程式碼我提交到github上,我衷心並且懇切的希望能有人把viewpager的切換效果也加入到這個專案中,向我發出合併申請。謝謝。

還得提一句,一直想寫一系列關於Android動畫的部落格,但是一直抽不出太多時間(短時間無法寫完),demo我已經寫完了,所以關於這部分以後部落格肯定會有,莫急莫急。