从事android开发有段时间了,总是说该写写技术博客了,分享知识的同时也能从中知道自己的不足,有挫折才会有动力,有争吵才会有成长,大家一起共勉吧。
直接进入主题吧,前两天正好看见一款App,对里面的Splash View给吸引住了, 像我们一般的App一般不会在Splash View花费太多的时间折腾,小公司大都功能至上,体验次之。从一个App的每个设计细节往往能够窥探出公司对产品和客户的责任心,当然了,这个有点扯远了,整个功能倒不是很难,我们一起来分析分析吧,么么哒!
首先我们从平台上下载有赞微小店,将.apk后缀改成.zip解压到任意文件夹,文件夹内容如下:
在res里面会找到相应的资源,往往大点的公司美工都是很不错的,图片也切的比较精美。
拿到想要的资源后,来分析分析设计需求吧:
1:每个子图片都是相对性的布局在自己的位子,并且以动画的形式以一定的时间间隔进行展示,凸显层次感。
2:滑动的过程中,后面的背景图不会跟着一起滑动,滑动的过程中背景图的透明度会随着页面的左右滑动正比渐变,直至完整滑出页面。
3:每滑到新页面都会将旧页面进行隐藏,并以动画的形式展现新页面,凸显层次感。
大概就这么多了,运行效果图如下,加深大家的理解:
下面我们一起用代码来实现:
主布局代码activity_main.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<RelativeLayout
android:id="@+id/relativelayout_first"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerInParent="true">
<ImageView
android:id="@+id/start1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:src="@mipmap/img_guide_page_1_star"
android:visibility="gone" />
<ImageView
android:id="@+id/start2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="45dp"
android:layout_marginTop="3dp"
android:src="@mipmap/img_guide_page_1_star"
android:visibility="gone" />
<ImageView
android:id="@+id/start3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="25dp"
android:layout_marginRight="35dp"
android:src="@mipmap/img_guide_page_1_star"
android:visibility="gone" />
<ImageView
android:id="@+id/first_page_img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/img_guide_page_1" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/relativelayout_second"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerInParent="true"
android:background="@mipmap/img_guide_page_bg">
<ImageView
android:id="@+id/second_bg1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="50dp"
android:src="@mipmap/img_guide_page_3_icon1" />
<ImageView
android:id="@+id/second_bg4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="50dp"
android:src="@mipmap/img_guide_page_3_icon4" />
<ImageView
android:id="@+id/second_bg2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="40dp"
android:layout_marginTop="80dp"
android:src="@mipmap/img_guide_page_3_icon2" />
<ImageView
android:id="@+id/second_bg3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="80dp"
android:layout_marginRight="40dp"
android:src="@mipmap/img_guide_page_3_icon3" />
<ImageView
android:id="@+id/second_bg5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="80dp"
android:layout_marginLeft="40dp"
android:src="@mipmap/img_guide_page_3_icon5" />
<ImageView
android:id="@+id/second_bg6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp"
android:layout_marginTop="80dp"
android:src="@mipmap/img_guide_page_3_icon6" />
<ImageView
android:id="@+id/second_bg7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@mipmap/img_guide_page_3_icon7" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/relativelayout_third"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerInParent="true"
android:background="@mipmap/img_guide_page_bg">
<ImageView
android:id="@+id/third_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dp"
android:src="@mipmap/img_guide_page_4_box" />
<ImageView
android:id="@+id/third_cash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:paddingBottom="40dp"
android:src="@mipmap/img_guide_page_4_cash" />
<ImageView
android:id="@+id/third_arrow_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="80dp"
android:src="@mipmap/img_guide_page_4_arrow_2" />
<ImageView
android:id="@+id/third_arrow_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="90dp"
android:src="@mipmap/img_guide_page_4_arrow_1" />
<ImageView
android:id="@+id/third_arrow_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="90dp"
android:src="@mipmap/img_guide_page_4_arrow_3" />
<ImageView
android:id="@+id/third_order"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="15dp"
android:paddingBottom="40dp"
android:src="@mipmap/img_guide_page_4_order" />
</RelativeLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"></android.support.v4.view.ViewPager>
<LinearLayout
android:id="@+id/linearlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:orientation="horizontal"
android:paddingBottom="10dp">
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:orientation="horizontal">
<Button
android:id="@+id/login"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/login_bg"
android:text="@string/login"
android:textColor="#f94041"
android:textSize="16sp" />
<Button
android:id="@+id/register"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_weight="1"
android:background="@drawable/register_bg"
android:text="@string/register"
android:textColor="@android:color/white"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
<FrameLayout
android:id="@+id/splash_bg"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:src="@mipmap/splash_shake" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:src="@mipmap/splash_brand" />
</FrameLayout>
</FrameLayout>
首先讲一下这个布局整体思路吧,也不难就是麻烦!–(,父类布局是FrameLayout,用这个的原因是最外层会遮罩一个InitSplashView图片,InitSplashView大概会显示2秒后将其状态设为INVISIABLE,然后显示的就是SplashView的,这个也是比较简单的做法了。当我们滑动ViewPager的时候ViewPager后面的背景是不会横着一起滑动的,所以后面的背景图肯定不是画在ViewPager所托管的子页面上,我们设置ViewPager的子页面背景为透明,这样后面的布局我们是可以看见的而且不会跟着ViewPager一起滑动,至于滑动过程后面的背景会跟着滑动偏移比例透明度会正比渐变,这个我们下面一起操作起来,很好玩的。
这边我们会有三个子页面,子页面里面的小图片都是以属性动画的形式进行展示的,当然我这边偷懒 ,minSdkVersion=11,哈哈,如果要兼容到3.0以下的话,还是乖乖的引入nineOldAndroids吧。
首先实现一个接口:
/** * Created by Administrator on 2015/9/17. * 动画公用接口<br/> */
public interface DefaultAnimator {
void startAnimator(View view, AnimatorCallback animatorCallback);
void withChangeAnimator(int position, float positionOffset, List<View> view, float positionOffsetPix, boolean flag);
}
接口两个方法分别为:startAnimator(启动动画), 2:withChangeAnimator(随着ViewPager的滑动正比渐变背景);
每个页面的动画单独抽成子类进行维护,这样可以减少代码耦合,也能提高代码的可维护度。
FirstAnimator:
package com.kakasure.splashdemo.animator;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.widget.ImageView;
import com.kakasure.splashdemo.R;
import com.kakasure.splashdemo.callback.AnimatorCallback;
import java.util.List;
/** * Created by Administrator on 2015/9/17. */
public class FirstAnimator implements DefaultAnimator {
public View baseView;
private ImageView start1;
private ImageView start2;
private ImageView start3;
private void initView() {
start1 = (ImageView) baseView.findViewById(R.id.start1);
start2 = (ImageView) baseView.findViewById(R.id.start2);
start3 = (ImageView) baseView.findViewById(R.id.start3);
start1.setVisibility(View.GONE);
start2.setVisibility(View.GONE);
start3.setVisibility(View.GONE);
}
@Override
public void startAnimator(final View view, final AnimatorCallback animatorCallback) {
if (view != null) {
baseView = view;
initView();
ImageView imageView = (ImageView) view.findViewById(R.id.first_page_img);
AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(imageView, "alpha", 0f, 1f);
ObjectAnimator scalexAnimator = ObjectAnimator.ofFloat(imageView, "scaleX", 0.4f, 1f);
ObjectAnimator scaleyAnimator = ObjectAnimator.ofFloat(imageView, "scaleY", 0.4f, 1f);
animatorSet.play(alphaAnimator).with(scalexAnimator).with(scaleyAnimator);
animatorSet.setDuration(1 * 500);
animatorSet.setInterpolator(new AccelerateInterpolator());
animatorSet.start();
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
animatorCallback.AnimatorStart(0);
}
@Override
public void onAnimationEnd(Animator animation) {
animatorCallback.AnimatorComplete(0);
startAnimatorSet(start1);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
}
private void startAnimatorSet(final View view) {
ObjectAnimator startAnimatorX1 = ObjectAnimator.ofFloat(view, "scaleX", 0f, 1f, 1.8f, 1f, 0.7f, 1.4f, 1.0f, 0.8f, 1f);
ObjectAnimator startAnimatorY1 = ObjectAnimator.ofFloat(view, "scaleY", 0f, 1f, 1.8f, 1f, 0.7f, 1.4f, 1.0f, 0.8f, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(200);
animatorSet.setInterpolator(new AccelerateInterpolator());
animatorSet.play(startAnimatorX1).with(startAnimatorY1);
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
view.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animator animation) {
switch (view.getId()) {
case R.id.start1:
startAnimatorSet(start2);
break;
case R.id.start2:
startAnimatorSet(start3);
break;
case R.id.start3:
// TODO NOTHING
break;
default:
break;
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
animatorSet.start();
}
@Override
public void withChangeAnimator(int position, float positionOffset, List<View> view, float positionOffsetPix, boolean flag) {
if (view != null) {
if (positionOffsetPix == 0) {
view.get(position).setAlpha(1f);
} else {
if (flag) {
view.get(position).setAlpha(1 - positionOffset);
} else {
view.get(position).setAlpha(positionOffset);
}
}
}
}
}
SecondAnimator.ThirdAnimator与上面显示雷同:
首先startAimator方法的触发时机为两种:
1:InitSplashView过渡两秒之后触发:
myHandler.sendEmptyMessageDelayed(1, 2 * 1000);
private Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
splashbg.setVisibility(View.GONE);
updateIndicatorStatus(0);
}
};
2:第二种触发方法完全依赖OnPageChangeListener的实现监听:
@Override
public void onPageSelected(int position) {
updateIndicatorStatus(position);
Log.i(TAG, "onPageSelected is called, position = " + position);
}
那我们来看下updateIndicatorStatus到底是干什么的:
public void updateIndicatorStatus(int position) {
currentPosition = position;
AnimatorManager.getInstance().startAnimator(position);
switch (position) {
case 0:
imgList.get(0).setBackgroundResource(R.mipmap.yindao_down);
imgList.get(1).setBackgroundResource(R.mipmap.yindao_on);
imgList.get(2).setBackgroundResource(R.mipmap.yindao_on);
break;
case 1:
imgList.get(1).setBackgroundResource(R.mipmap.yindao_down);
imgList.get(0).setBackgroundResource(R.mipmap.yindao_on);
imgList.get(2).setBackgroundResource(R.mipmap.yindao_on);
break;
case 2:
imgList.get(2).setBackgroundResource(R.mipmap.yindao_down);
imgList.get(1).setBackgroundResource(R.mipmap.yindao_on);
imgList.get(0).setBackgroundResource(R.mipmap.yindao_on);
break;
default:
break;
}
}
这里我们会根据滑动监听动态改变Indicator Icon的背景图,同时我们会触发相应页面的初始动画,这里动画的统一管理我们会放在AnimatorManager进行管理:
代码如下:
package com.kakasure.splashdemo.manager;
import android.util.SparseArray;
import android.view.View;
import com.kakasure.splashdemo.callback.AnimatorCallback;
import com.kakasure.splashdemo.animator.AnimatorFactory;
import java.util.ArrayList;
import java.util.List;
/** * Created by Administrator on 2015/9/17. * 动画管理类<br/> * * @author dashentao * @date 2015 9-17 * @since V 1.0 */
public class AnimatorManager implements AnimatorCallback {
// 管理View的集合
private List<View> viewList = new ArrayList<View>();
private static AnimatorManager mAnimatorManager;
private static Object object = new Object();
private SparseArray<Boolean> sparseArray = new SparseArray<Boolean>();
public static AnimatorManager getInstance() {
if (mAnimatorManager == null) {
synchronized (object) {
if (mAnimatorManager == null) {
mAnimatorManager = new AnimatorManager();
}
}
}
return mAnimatorManager;
}
public void add(View view) {
if (viewList != null) {
viewList.add(view);
}
}
public void addAll(List<View> view) {
if (viewList != null) {
viewList.clear();
viewList.addAll(view);
}
}
/** * ViewPager滑动式渐变动画<br/> * * @param position * @param positionOffset */
public void withChangeAnimator(int position, float positionOffset, float positionOffsetPix, boolean flag) {
if (sparseArray != null) {
if (sparseArray.get(position) != null && sparseArray.get(position)) {
AnimatorFactory.getInstance(position).withChangeAnimator(position, positionOffset, viewList, positionOffsetPix, flag);
}
}
}
/** * 启动相应子页面的动画<br/> * * @param position */
public void startAnimator(int position) {
// 对动画做隐藏处理
if (viewList != null && viewList.size() > 0) {
for (int i = 0; i < viewList.size(); i++) {
if (i == position) {
viewList.get(i).setVisibility(View.VISIBLE);
} else {
viewList.get(i).setVisibility(View.INVISIBLE);
}
}
}
AnimatorFactory.getInstance(position).startAnimator(viewList.get(position), this);
}
@Override
public void AnimatorComplete(int position) {
if (sparseArray != null) {
sparseArray.put(position, true);
}
}
@Override
public void AnimatorStart(int position) {
if (sparseArray != null) {
sparseArray.put(position, false);
}
}
}
在startAnimtor里面我们会隐藏其他页面,显示当前页面。这里我们通过简单工厂得到动画操作实例:
package com.kakasure.splashdemo.animator;
import android.util.Log;
/** * Created by Administrator on 2015/9/17. * 简单工厂类<br/> */
public class AnimatorFactory {
public static final String TAG = AnimatorFactory.class.getSimpleName();
public static DefaultAnimator getInstance(int position) {
switch (position) {
case 0:
return new FirstAnimator();
case 1:
return new SecondAnimator();
case 2:
return new ThirdAnimator();
default:
Log.i(TAG, "you know, it will not be happened!");
break;
}
return null;
}
}
得到相应实例时候会相应的通过多态调用子类中StartAimator方法,顾客只需要调用某个方法,具体的逻辑子类自己去实现,顾客与用户进行解耦。
我们再来看下如何让ViewPager的子页面跟随滑动正比渐变,这个我们就要去了解OnPageChangeListener这个接口实现方法的具体含义了:
1:public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
——-时刻监听ViewPager的滑动状态,positionOffset为滑动的比例0f-1f,positionOffsetPixels为当前页面偏移的像素位置 。
2: public void onPageSelected(int position)
——-滑动完成之后掉用。
3: public void onPageScrollStateChanged(int state)
——-监听滑动状态:state==1时默示正在滑动,state==2时默示滑动完毕了,state==0时默示什么都没做。
然后思路就来了,我们根据positionOffset来动态设置整个子布局的ahpla(透明度),这样就可以达到效果了,开始动手吧。
代码如下:
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
Log.i(TAG, "position = " + position);
boolean flag = false;
if (position == currentPosition) {
flag = true;
} else {
flag = false;
}
AnimatorManager.getInstance().withChangeAnimator(currentPosition, positionOffset, positionOffsetPixels, flag);
}
在FirstAnimator里面自己实现:
@Override
public void withChangeAnimator(int position, float positionOffset, List<View> view, float positionOffsetPix, boolean flag) {
if (view != null) {
if (positionOffsetPix == 0) {
view.get(position).setAlpha(1f);
} else {
if (flag) {
view.get(position).setAlpha(1 - positionOffset);
} else {
view.get(position).setAlpha(positionOffset);
}
}
}
}
这里面实现的过程中遇到一些问题,ViewPager页面滑动过程中PositionOffset渐变比例会随着滑动方向而不同,向左滑动比例会从1f-0f, 向右滑动比例会从0f-1f, 但是向左滑动时,position会是上个页面的position,不调试不知道,调试完了之后吓一跳,没办法,凡事都得实践才能出真理,所以这边做了特殊处理,还有就是当positionOffsetPix == 0时,我们会设置alpha为不透明,这样能保证当滑动到一半时松手自然回弹到当前页面布局透明度为0;
主MainActivity:
package com.kakasure.splashdemo.ui;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.kakasure.splashdemo.R;
import com.kakasure.splashdemo.manager.ActManager;
import com.kakasure.splashdemo.manager.AnimatorManager;
import java.util.ArrayList;
import java.util.List;
/** * Created by Administrator on 2015/9/16. * * @author dashentao * @date 2015 9-16 * @since V 1.0 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private String TAG = MainActivity.this.getClass().getSimpleName();
private ViewPager viewPager;
private Button login;
private Button register;
private LinearLayout linearLayout;
private RelativeLayout relativeLayoutFirst;
private RelativeLayout relativeLayoutSecond;
private RelativeLayout relativeLayoutThrid;
private FrameLayout splashbg;
private List<ImageView> imgList = new ArrayList<ImageView>();
private List<Fragment> fragList = new ArrayList<Fragment>();
private int currentPosition = -1;
private Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
splashbg.setVisibility(View.GONE);
updateIndicatorStatus(0);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActManager.getInstance().pushActivity(this);
initView();
initListener();
initAdapter();
init();
}
public void initListener() {
login.setOnClickListener(this);
register.setOnClickListener(this);
viewPager.setOnPageChangeListener(new MyPageChangeListener());
}
public void initView() {
viewPager = (ViewPager) findViewById(R.id.viewpager);
login = (Button) findViewById(R.id.login);
register = (Button) findViewById(R.id.register);
linearLayout = (LinearLayout) findViewById(R.id.linearlayout);
relativeLayoutFirst = (RelativeLayout) findViewById(R.id.relativelayout_first);
relativeLayoutSecond = (RelativeLayout) findViewById(R.id.relativelayout_second);
relativeLayoutThrid = (RelativeLayout) findViewById(R.id.relativelayout_third);
splashbg = (FrameLayout) findViewById(R.id.splash_bg);
}
/** * 初始化适配器<br/> */
public void initAdapter() {
FragmentManager fragmentManager = getSupportFragmentManager();
MyAdapter myAdapter = new MyAdapter(fragmentManager);
for (int i = 0; i < 3; i++) {
SplashFragment splashFragment = SplashFragment.newInstance(getResources().getStringArray(R.array.titles)[i]);
fragList.add(splashFragment);
}
myAdapter.list.clear();
myAdapter.list.addAll(fragList);
viewPager.setAdapter(myAdapter);
}
public void init() {
for (int i = 0; i < fragList.size(); i++) {
ImageView imageView = new ImageView(this);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
linearLayout.addView(imageView, layoutParams);
imgList.add(imageView);
}
List<View> view = new ArrayList<View>();
view.add(relativeLayoutFirst);
view.add(relativeLayoutSecond);
view.add(relativeLayoutThrid);
AnimatorManager.getInstance().addAll(view);
myHandler.sendEmptyMessageDelayed(1, 2 * 1000);
}
public void updateIndicatorStatus(int position) {
currentPosition = position;
AnimatorManager.getInstance().startAnimator(position);
switch (position) {
case 0:
imgList.get(0).setBackgroundResource(R.mipmap.yindao_down);
imgList.get(1).setBackgroundResource(R.mipmap.yindao_on);
imgList.get(2).setBackgroundResource(R.mipmap.yindao_on);
break;
case 1:
imgList.get(1).setBackgroundResource(R.mipmap.yindao_down);
imgList.get(0).setBackgroundResource(R.mipmap.yindao_on);
imgList.get(2).setBackgroundResource(R.mipmap.yindao_on);
break;
case 2:
imgList.get(2).setBackgroundResource(R.mipmap.yindao_down);
imgList.get(1).setBackgroundResource(R.mipmap.yindao_on);
imgList.get(0).setBackgroundResource(R.mipmap.yindao_on);
break;
default:
break;
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.login:
// 登录状态
break;
case R.id.register:
// 用户注册
break;
default:
Log.i(TAG, "It will not happened!");
break;
}
}
/** * 滑动页面监视器 */
public class MyPageChangeListener implements ViewPager.OnPageChangeListener {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// Log.i(TAG, "positionOffset is =" + positionOffset);
// Log.i(TAG, "positionOffsetPixels is = " + positionOffsetPixels);
Log.i(TAG, "position = " + position);
boolean flag = false;
if (position == currentPosition) {
flag = true;
} else {
flag = false;
}
AnimatorManager.getInstance().withChangeAnimator(currentPosition, positionOffset, positionOffsetPixels, flag);
}
@Override
public void onPageSelected(int position) {
updateIndicatorStatus(position);
Log.i(TAG, "onPageSelected is called, position = " + position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
/** * ViewPager适配器 */
public class MyAdapter extends FragmentPagerAdapter {
List<Fragment> list = new ArrayList<Fragment>();
public MyAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return list.get(position);
}
@Override
public int getCount() {
return list.size();
}
}
}
再有就是动画方面了,无非就是对属性的一些操作;
具体涉及到这些:
1:透明度,X,Y轴的缩放同步播放:
AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(imageView, "alpha", 0f, 1f);
ObjectAnimator scalexAnimator = ObjectAnimator.ofFloat(imageView, "scaleX", 0.4f, 1f);
ObjectAnimator scaleyAnimator = ObjectAnimator.ofFloat(imageView, "scaleY", 0.4f, 1f);
animatorSet.play(alphaAnimator).with(scalexAnimator).with(scaleyAnimator);
animatorSet.setDuration(1 * 500);
animatorSet.setInterpolator(new AccelerateInterpolator());
animatorSet.start();
2:箭头显示的动画:
float currentX3 = view.getTranslationX();
float currentY3 = view.getTranslationY();
ObjectAnimator arrowX3 = ObjectAnimator.ofFloat(view, "translationX", currentX3 - AppUtils.dip2px(ActManager.getInstance().getCurrentActivity(), 8), currentX3);
ObjectAnimator arrowY3 = ObjectAnimator.ofFloat(view, "translationY", currentY3 + AppUtils.dip2px(ActManager.getInstance().getCurrentActivity(), 8), currentY3);
animatorSet.play(arrowX3).with(arrowY3);
等等,有动画基础的同学这些都是小儿科了。
还有一个地方比较重要:
就是启动子页面动画的时候,不会去触发ViewPager滑动引起的透明度改变,这样会避免闪烁现象。
这里主要是监听启动动画的回调:
当然我们在AnimatorManger会实现一个接口:
package com.kakasure.splashdemo.callback;
/** * Created by Administrator on 2015/9/17. */
public interface AnimatorCallback {
void AnimatorComplete(int position);
void AnimatorStart(int position);
}
然后将接口注册到FirstAnimator中,通过监听动画的执行状态通过callback接口回调给AnimatorManager;
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
animatorCallback.AnimatorStart(0);
}
@Override
public void onAnimationEnd(Animator animation) {
animatorCallback.AnimatorComplete(0);
startAnimatorSet(start1);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
我们在启动withChangeAnimator的时候会去判断回调状态:
/** * ViewPager滑动式渐变动画<br/> * * @param position * @param positionOffset */
public void withChangeAnimator(int position, float positionOffset, float positionOffsetPix, boolean flag) {
if (sparseArray != null) {
if (sparseArray.get(position) != null && sparseArray.get(position)) {
AnimatorFactory.getInstance(position).withChangeAnimator(position, positionOffset, viewList, positionOffsetPix, flag);
}
}
}
每个页面的动画滑动状态会通过SparseArray进行维护:
private SparseArray<Boolean> sparseArray = new SparseArray<Boolean>();
尼玛,写博客比写代码累多了,终于倒腾倒腾的差不多了,由于第一次写技术博客,有很多小瑕疵,当然由于代码只是自己闲暇之余写的Demo,性能方面还是有待优化的,希望自己坚持下去,做一个懂得记录的Coder。
Github下载地址:https://github.com/dashentao1989/SplashView.git