Android之app引導頁(背景圖片切換加各個頁面動畫效果)
阿新 • • 發佈:2019-02-10
轉載:http://blog.csdn.net/lowprofile_coding/article/details/48037095
先看效果圖:
1.顯示三個頁面的Activity 用view pager去載入三個fragment實現,控制點點點的切換,監聽view pager的切換,控制fragment動畫的開始跟結束,重寫了view pager,實現了背景圖片的移動效果.
2.重寫viewpager 在dispatchDraw方法中控制顯示的背景圖片區域,/** * 主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); } } } }
3.主體佈局檔案 上面放一個自定義的viewpager 下面放一個顯示點點的RelativeLayout/** * 重寫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); } }
4.ViewPager介面卡<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>
/**
* 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動畫布局就能搞定.之前一直想辦法用兩個動畫實現
點選原始碼下載