1. 程式人生 > >Android之app引導頁(背景圖片切換加各個頁面動畫效果)

Android之app引導頁(背景圖片切換加各個頁面動畫效果)

轉載:http://blog.csdn.net/lowprofile_coding/article/details/48037095

先看效果圖:


1.顯示三個頁面的Activity  用view pager去載入三個fragment實現,控制點點點的切換,監聽view pager的切換,控制fragment動畫的開始跟結束,重寫了view pager,實現了背景圖片的移動效果.

/**
 * 主Activity
 * @author ansen
 * @create time 2015-08-07
 */
public class KaKaLauncherActivity extends FragmentActivity {
	private GuideViewPager vPager;
	private List<LauncherBaseFragment> list = new ArrayList<LauncherBaseFragment>();
	private BaseFragmentAdapter adapter;

	private ImageView[] tips;
	private int currentSelect; 
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_luancher_main);
		
		//初始化點點點控制元件
		ViewGroup group = (ViewGroup)findViewById(R.id.viewGroup);
		tips = new ImageView[3];
		for (int i = 0; i < tips.length; i++) {
			ImageView imageView = new ImageView(this);
			imageView.setLayoutParams(new LayoutParams(10, 10));
			if (i == 0) {
				imageView.setBackgroundResource(R.drawable.page_indicator_focused);
			} else {
				imageView.setBackgroundResource(R.drawable.page_indicator_unfocused);
			}
			tips[i]=imageView;

			LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
			layoutParams.leftMargin = 20;//設定點點點view的左邊距
			layoutParams.rightMargin = 20;//設定點點點view的右邊距
			group.addView(imageView,layoutParams);
		}
		
		//獲取自定義viewpager 然後設定背景圖片
		vPager = (GuideViewPager) findViewById(R.id.viewpager_launcher);
		vPager.setBackGroud(BitmapFactory.decodeResource(getResources(),R.drawable.bg_kaka_launcher));

		/**
		 * 初始化三個fragment  並且新增到list中
		 */
		RewardLauncherFragment rewardFragment = new RewardLauncherFragment();
		PrivateMessageLauncherFragment privateFragment = new PrivateMessageLauncherFragment();
		StereoscopicLauncherFragment stereoscopicFragment = new StereoscopicLauncherFragment();
		list.add(rewardFragment);
		list.add(privateFragment);
		list.add(stereoscopicFragment);

		adapter = new BaseFragmentAdapter(getSupportFragmentManager(),list);
		vPager.setAdapter(adapter);
		vPager.setOffscreenPageLimit(2);
		vPager.setCurrentItem(0);
		vPager.setOnPageChangeListener(changeListener);
	}
	
	/**
	 * 監聽viewpager的移動
	 */
	OnPageChangeListener changeListener=new OnPageChangeListener() {
		@Override
		public void onPageSelected(int index) {
			setImageBackground(index);//改變點點點的切換效果
			LauncherBaseFragment fragment=list.get(index);
			
			list.get(currentSelect).stopAnimation();//停止前一個頁面的動畫
			fragment.startAnimation();//開啟當前頁面的動畫
			
			currentSelect=index;
		}
		
		@Override
		public void onPageScrolled(int arg0, float arg1, int arg2) {}
		@Override
		public void onPageScrollStateChanged(int arg0) {}
	};
	
	/**
	 * 改變點點點的切換效果
	 * @param selectItems
	 */
	private void setImageBackground(int selectItems) {
		for (int i = 0; i < tips.length; i++) {
			if (i == selectItems) {
				tips[i].setBackgroundResource(R.drawable.page_indicator_focused);
			} else {
				tips[i].setBackgroundResource(R.drawable.page_indicator_unfocused);
			}
		}
	}
}
2.重寫viewpager   在dispatchDraw方法中控制顯示的背景圖片區域,
/**
 * 重寫ViewPager  主要做一個切換背景的功能
 * @author ansen
 * @create time 2015-08-07
 */
public class GuideViewPager extends ViewPager {
	private Bitmap bg;
	private Paint b = new Paint(1);
	
	public GuideViewPager(Context context) {
		super(context);
	}

	public GuideViewPager(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	protected void dispatchDraw(Canvas canvas) {
		if (this.bg != null) {
			int width = this.bg.getWidth();
			int height = this.bg.getHeight();
			int count = getAdapter().getCount();
			int x = getScrollX();
			// 子View中背景圖片需要顯示的寬度,放大背景圖或縮小背景圖。
			int n = height * getWidth() / getHeight();
			
			/**
			 * (width - n) / (count - 1)表示除去顯示第一個ViewPager頁面用去的背景寬度,剩餘的ViewPager需要顯示的背景圖片的寬度。
			 * getWidth()等於ViewPager一個頁面的寬度,即手機螢幕寬度。在該計算中可以理解為滑動一個ViewPager頁面需要滑動的畫素值。
			 * ((width - n) / (count - 1)) /getWidth()也就表示ViewPager滑動一個畫素時,背景圖片滑動的寬度。
			 * x * ((width - n) / (count - 1)) /  getWidth()也就表示ViewPager滑動x個畫素時,背景圖片滑動的寬度。
			 * 背景圖片滑動的寬度的寬度可以理解為背景圖片滑動到達的位置。
			 */
			int w = x * ((width - n) / (count - 1)) / getWidth();
			canvas.drawBitmap(this.bg, new Rect(w, 0, n + w, height), new Rect( x, 0, x + getWidth(), getHeight()), this.b);
		}
		super.dispatchDraw(canvas);
	}
	
	public void setBackGroud(Bitmap paramBitmap) {
		this.bg = paramBitmap;
		this.b.setFilterBitmap(true);
	}
}
3.主體佈局檔案  上面放一個自定義的viewpager  下面放一個顯示點點的RelativeLayout
<RelativeLayout 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" >

    <com.example.view.GuideViewPager
        android:id="@+id/viewpager_launcher"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <LinearLayout
            android:id="@+id/viewGroup"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="30dp"
            android:gravity="center_horizontal"
            android:orientation="horizontal" />
    </RelativeLayout>

</RelativeLayout>
4.ViewPager介面卡
/**
 * Viewpager介面卡
 * @author apple
 *
 */
public class BaseFragmentAdapter extends FragmentStatePagerAdapter {
	private List<LauncherBaseFragment>list;
	public BaseFragmentAdapter(FragmentManager fm, List<LauncherBaseFragment> list) {
		super(fm);
		this.list = list;
	}

	public BaseFragmentAdapter(FragmentManager fm) {
		super(fm);
	}

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

	@Override
	public int getCount() {
		return list.size();
	}
}
5.Fragment抽象類 有兩個抽象方法,開啟動畫跟停止動畫  所有的Fragment都繼承這個類  Viewpager切換的時候可以更好的控制每個Fragment開啟動畫,結束動畫
/**
 * Fragment抽象類
 * @author ansen
 * 
 */
public abstract class LauncherBaseFragment extends Fragment{
	public abstract void  startAnimation();
	public abstract void  stopAnimation();
}
6.打賞頁Fragment  三個動畫效果  硬幣向下移動動畫+打賞圖片縮放動畫+改變打賞圖片透明度然後隱藏圖片
/**
 * 打賞頁面
 * @author ansen
 * @create time 2015-08-07
 */
public class RewardLauncherFragment extends LauncherBaseFragment{
	private ImageView ivReward;
	private ImageView ivGold;
	
	private Bitmap goldBitmap;
	private boolean started;//是否開啟動畫(ViewPage滑動時候給這個變數賦值)
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
		View rooView=inflater.inflate(R.layout.fragment_reward_launcher, null);
		ivGold=(ImageView) rooView.findViewById(R.id.iv_gold);
		ivReward=(ImageView) rooView.findViewById(R.id.iv_reward);
		
		//獲取硬幣的高度
		goldBitmap=BitmapFactory.decodeResource(getActivity().getResources(),R.drawable.icon_gold);
		startAnimation();
		return rooView;
	}
	
	public void startAnimation(){
		started=true;
		
		//向下移動動畫 硬幣的高度*2+80   
		TranslateAnimation translateAnimation=new TranslateAnimation(0,0,0,goldBitmap.getHeight()*2+80);
		translateAnimation.setDuration(500);
		translateAnimation.setFillAfter(true);
		
		ivGold.startAnimation(translateAnimation);
		translateAnimation.setAnimationListener(new AnimationListener() {
			@Override
			public void onAnimationStart(Animation animation) {}
			@Override
			public void onAnimationEnd(Animation animation){
				if(started){
					ivReward.setVisibility(View.VISIBLE);
					//硬幣移動動畫結束開啟縮放動畫
		            Animation anim=AnimationUtils.loadAnimation(getActivity(),R.anim.reward_launcher);  
		            ivReward.startAnimation(anim);
		            anim.setAnimationListener(new AnimationListener(){
		                @Override  
		                public void onAnimationStart(Animation animation) {}  
		                @Override  
		                public void onAnimationRepeat(Animation animation) {}  
		                @Override  
		                public void onAnimationEnd(Animation animation) {
		                		//縮放動畫結束 開啟改變透明度動畫
		                		AlphaAnimation alphaAnimation=new AlphaAnimation(1,0);
		                		alphaAnimation.setDuration(1000);
		                		ivReward.startAnimation(alphaAnimation);
		                		alphaAnimation.setAnimationListener(new AnimationListener() {
									@Override
									public void onAnimationStart(Animation animation) {}
									@Override
									public void onAnimationRepeat(Animation animation) {}
									@Override
									public void onAnimationEnd(Animation animation) {
										//透明度動畫結束隱藏圖片
										ivReward.setVisibility(View.GONE);
									}
							});
		                }
		            });
				}
			}
			@Override
			public void onAnimationRepeat(Animation animation) {}
		});
	}
	
	@Override
	public void stopAnimation(){
		started=false;//結束動畫時標示符設定為false
		ivGold.clearAnimation();//清空view上的動畫
	}
}
7.私信頁面   四個動畫效果   並且四個動畫都相同,其實只要我們實現了一個,其他的基本都很容易了.   依次實現四個圖片的放大然後還原
/**
 * 私信
 * @author ansen
 */
public class PrivateMessageLauncherFragment extends LauncherBaseFragment{
	private ImageView ivLikeVideo,ivThinkReward,ivThisWeek,ivWatchMovie;
	
	private Animation likeAnimation,thinkAnimation,watchAnimation,thisWeekAnimation;
	
	private boolean started;//是否開啟動畫
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
		View rooView=inflater.inflate(R.layout.fragment_private_message_launcher, null);
		
		ivLikeVideo=(ImageView) rooView.findViewById(R.id.iv_private_message_like_video);
		ivThinkReward=(ImageView) rooView.findViewById(R.id.iv_private_message_think_reward);
		ivWatchMovie=(ImageView) rooView.findViewById(R.id.iv_private_message_watch_movie);
		ivThisWeek=(ImageView) rooView.findViewById(R.id.private_message_this_week);
		return rooView;
	}
	
	public void stopAnimation(){
		//動畫開啟標示符設定成false   
		started=false;
		/**
		 * 清空所有控制元件上的動畫
		 */
		ivLikeVideo.clearAnimation();
		ivThinkReward.clearAnimation();
		ivWatchMovie.clearAnimation();
		ivThisWeek.clearAnimation();
	}
	
	
	public void startAnimation(){
		started=true;
		
		/**
		 * 每次開啟動畫前先隱藏控制元件
		 */
		ivLikeVideo.setVisibility(View.GONE);
		ivThinkReward.setVisibility(View.GONE);
		ivWatchMovie.setVisibility(View.GONE);
		ivThisWeek.setVisibility(View.GONE);
		
		new Handler().postDelayed(new Runnable() {//延時0.5秒之後開啟喜歡視訊動畫
			@Override
			public void run(){
				if(started)
					likeVideoAnimation();
			}
		},500);
	}
	
	/**
	 * 好喜歡你的視訊
	 */
	private void likeVideoAnimation(){
		ivLikeVideo.setVisibility(View.VISIBLE);
		
		likeAnimation = AnimationUtils.loadAnimation(getActivity(),R.anim.private_message_launcher);
		ivLikeVideo.startAnimation(likeAnimation);//開啟動畫
		likeAnimation.setAnimationListener(new AnimationListener(){  
            @Override  
            public void onAnimationStart(Animation animation) {}  
            @Override  
            public void onAnimationRepeat(Animation animation) {}  
            @Override  
            public void onAnimationEnd(Animation animation) {//監聽動畫結束
	            	if(started)
	            		thinkReward();
            }  
        }); 
	}
	
	/**
	 * 謝謝你的打賞
	 */
	private void thinkReward(){
		ivThinkReward.setVisibility(View.VISIBLE);
		thinkAnimation = AnimationUtils.loadAnimation(getActivity(),R.anim.private_message_launcher);
		ivThinkReward.startAnimation(thinkAnimation);
		thinkAnimation.setAnimationListener(new AnimationListener(){  
            @Override  
            public void onAnimationStart(Animation animation) {}  
            @Override  
            public void onAnimationRepeat(Animation animation) {}  
            @Override  
            public void onAnimationEnd(Animation animation) {
            	if(started)
            		watchMovie();
            }  
        }); 
	}
	
	/**
	 * 一起看個電影唄
	 */
	private void watchMovie(){
		ivWatchMovie.setVisibility(View.VISIBLE);
		watchAnimation = AnimationUtils.loadAnimation(getActivity(),R.anim.private_message_launcher);
		ivWatchMovie.startAnimation(watchAnimation);
		watchAnimation.setAnimationListener(new AnimationListener(){  
            @Override  
            public void onAnimationStart(Animation animation) {}  
            @Override  
            public void onAnimationRepeat(Animation animation) {}  
            @Override  
            public void onAnimationEnd(Animation animation) {
            	if(started)
            		thisWeek();
            }  
        }); 
	}
	
	/**
	 * 好啊  這週末有空
	 */
	private void thisWeek(){
		ivThisWeek.setVisibility(View.VISIBLE);
		thisWeekAnimation = AnimationUtils.loadAnimation(getActivity(),R.anim.private_message_launcher);  
		ivThisWeek.startAnimation(thisWeekAnimation);
	}
}
8.最後一個引導頁  就兩個動畫  圖片的放大跟縮小,其實用xml佈局的話一個動畫就能搞定,跟私信頁面的動畫差不多.小夥伴寫的程式碼.這裡換了一種方式.程式碼比較多.
/**
 * 最後一個
 * @author apple
 */
public class StereoscopicLauncherFragment extends LauncherBaseFragment implements OnClickListener{
	private static final float ZOOM_MAX = 1.3f;
	private static final  float ZOOM_MIN = 1.0f;
	
	private ImageView imgView_immediate_experience;
    
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
		View rooView=inflater.inflate(R.layout.fragment_stereoscopic_launcher, null);
		imgView_immediate_experience=(ImageView) rooView.findViewById(R.id.imgView_immediate_experience);
		imgView_immediate_experience.setOnClickListener(this);
		return rooView;
	}
	
    public void playHeartbeatAnimation(){
    		/**
    		 * 放大動畫
    		 */
        AnimationSet animationSet = new AnimationSet(true);
		animationSet.addAnimation(new ScaleAnimation(ZOOM_MIN, ZOOM_MAX, ZOOM_MIN, ZOOM_MAX, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f));
        animationSet.addAnimation(new AlphaAnimation(1.0f, 0.8f));
 
        animationSet.setDuration(500);
        animationSet.setInterpolator(new AccelerateInterpolator());
        animationSet.setFillAfter(true);
 
        animationSet.setAnimationListener(new AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            }
 
            @Override
            public void onAnimationRepeat(Animation animation) {
            }
 
            @Override
            public void onAnimationEnd(Animation animation) {
	        		/**
	        		 * 縮小動畫
	        		 */
                AnimationSet animationSet = new AnimationSet(true);
                animationSet.addAnimation(new ScaleAnimation(ZOOM_MAX, ZOOM_MIN, ZOOM_MAX,ZOOM_MIN, Animation.RELATIVE_TO_SELF, 0.5f,Animation.RELATIVE_TO_SELF, 0.5f));
                animationSet.addAnimation(new AlphaAnimation(0.8f, 1.0f));
                animationSet.setDuration(600);
                animationSet.setInterpolator(new DecelerateInterpolator());
                animationSet.setFillAfter(false);
                 // 實現心跳的View
                imgView_immediate_experience.startAnimation(animationSet);
            }
        });
         // 實現心跳的View
        imgView_immediate_experience.startAnimation(animationSet);
    } 

	@Override
	public void onClick(View v) {
//		Intent intent = new Intent();
//		intent.setClass(getActivity(),MainActivity.class);
//		startActivity(intent);
//		getActivity().finish();
	}

	@Override
	public void startAnimation() {
		playHeartbeatAnimation();
	}

	@Override
	public void stopAnimation() {
		
	}
}

最後總結:以上就是三個引導頁的核心程式碼了,還有一些佈局檔案,動畫效果的佈局檔案我就不一一貼出來的,大家可以去下載我的原始碼,在這個過程中碰到的幾個大的問題說明一下.

1.viewpager切換的時候要結束上個fragment的動畫   我是通過boolean變數去控制的

2.背景圖片移動的效果    之前自己走了很多彎路,後面在網上找了一個demo拿過來用了.因為大家都有開源精神所以這裡省了很多功夫

3.圖片放大縮小以前居然不知道一個xml動畫布局就能搞定.之前一直想辦法用兩個動畫實現

點選原始碼下載