android splash引导页的实现

splash引导页是最常见不过的效果了,实现的方式也有很多,也比较容易实现,而对于自己来说通过了解不同的实现方式,比较其不同,同时也拓宽自己的思路,在不同的需求下选在自己觉得ok的实现方式。

Handler消息延迟方式

如果引导页的效果比较简单,就一张图片通过时间的延迟进入主程序,这样子通过Handler消息延迟就可以实现了;

public class SplashActivity extends AppCompatActivity {
    //停留的时长
    private static final long DELAY_TIME = 3000;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //进入主程序页面
                startActivity(new Intent(SplashActivity.this, MainActivity.class));
                finish();
            }
        }, DELAY_TIME);
    }
}

这样子就实现了,效果简单,就没有必要用复杂的方式实现了,如果想在右上角添加一个圆,然后动态显示时间,可以参考自定义view仿KeepApp Splash广告效果;

android splash引导页的实现_第1张图片
GIF.gif

ViewPager+fragment的方式

接下来是ViewPager+fragment的方式实现,这也是开发中最常用的实现方式;
这里是将viewpager和底部的指示器封装在了一个自定义的布局容器中,然后通过自定义布局容器暴露的方法进行相对应的设置;

public class SplashLayout extends FrameLayout {
    private ViewPager viewPager;
    private LinearLayout linearLayout;
    private int viewSize = 0;
    //指示器距离底部的间距
    private int pointBottomMargin;
    //指示器大小
    private int pointSize;
    //指示器右边间距
    private int pointRightMargin;
    //是否显示底部指示器
    private boolean showIndicator;

    public SplashLayout(Context context) {
        this(context, null);
    }

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

    public SplashLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
        initView();
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SplashLayout);
        pointBottomMargin = (int) array.getDimension(R.styleable.SplashLayout_bottomPointBottomMargin, dip2px(100));
        pointSize = (int) array.getDimension(R.styleable.SplashLayout_pointSize, dip2px(10));
        pointRightMargin = (int) array.getDimension(R.styleable.SplashLayout_pointRightMargin, dip2px(20));
        showIndicator = array.getBoolean(R.styleable.SplashLayout_showIndicator, true);
        array.recycle();
    }

    /**
     * 初始化viewpager 和底部指示器
     */
    @SuppressLint("ResourceType")
    private void initView() {
        //实例化viewpager
        viewPager = new ViewPager(getContext());
        //这里需要设置viewpager的id 不设置会报错
        viewPager.setId(1);
        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        viewPager.setLayoutParams(lp);
        //实例化底部指示器容器
        linearLayout = new LinearLayout(getContext());
        FrameLayout.LayoutParams indoctorLp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        linearLayout.setOrientation(LinearLayout.HORIZONTAL);
        linearLayout.setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
        indoctorLp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
        indoctorLp.bottomMargin = pointBottomMargin;

        linearLayout.setLayoutParams(indoctorLp);

        addView(viewPager);
        addView(linearLayout);
        initEvent();
    }

    private void initEvent() {
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float v, int i1) {
                if (viewSize == 0) {
                    return;
                }
                for (int i = 0; i < viewSize; i++) {
                    View childAt = linearLayout.getChildAt(i);
                    if(childAt==null){
                        continue;
                    }
                    childAt.setBackgroundResource(i == position ? R.drawable.dot_select : R.drawable.dot_normal);
                }
            }

            @Override
            public void onPageSelected(int i) {

            }

            @Override
            public void onPageScrollStateChanged(int i) {

            }
        });
    }

    /**
     * @param
     */
    public  void showSplash(T adapter, int fragmentSize) {
        this.viewSize = fragmentSize;
        //给viewpager添加adapter
        viewPager.setAdapter(adapter);
        if (showIndicator) {
            initIndicator();
        }
    }

    /**
     * 初始化指示器
     */
    private void initIndicator() {
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(pointSize, pointSize);
        for (int i = 0; i < viewSize; i++) {
            View view = new View(getContext());
            view.setBackgroundResource(i == 0 ? R.drawable.dot_select : R.drawable.dot_normal);
            lp.rightMargin = pointRightMargin;
            view.setId(i);
            view.setLayoutParams(lp);
            linearLayout.addView(view);
        }
    }

    private int dip2px(int dip) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
    }
}

这样子就没有必要在activity或者fragment写大量的逻辑,将代码隔离开来,在activity中使用时就只需要调用showSplash方法并传入相应的参数,同时可以通过下面这些自定义属性设置引导页指示器是否显示、指示器的大小等;具体的可以根据项目的需要进行调整和修改;


    
        
        
        
        
    

public class ViewPagerActivity extends AppCompatActivity {
    private int[] bgRes = {R.mipmap.viewpager1, R.mipmap.viewpager2, R.mipmap.viewpager3, R.mipmap.viewpager4};
    private ViewPagerAdapter adapter;
    private List fragments;
    private SplashLayout splashLayout;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_viewpager);
        splashLayout = findViewById(R.id.splash_layout);
        fragments = new ArrayList<>();

        for (int i = 0; i < bgRes.length; i++) {
            ContentFragment fragment;
            if (i == (bgRes.length - 1)) {
                fragment = ContentFragment.getInstance(bgRes[i], true);
            } else {
                fragment = ContentFragment.getInstance(bgRes[i], false);
            }
            fragments.add(fragment);
        }
        adapter = new ViewPagerAdapter(getSupportFragmentManager(), fragments);
        splashLayout.showSplash(adapter, fragments.size());
    }
}

activity里面的代码就比较少,也就比较整洁了,ImageView设置背景这里是加载的本地资源图片,如果加载网络图片,可以将那里的逻辑换成一些第三方图片加载库来实现;这样viewpager+fragment的方式就实现引导页效果了;


GIF.gif

ViewFlipper方式

ViewFlipper是系统提供的一个切换控件,效果类似ViewPager,有不少日历效果就是采用ViewFlipper来实现的,这里也用ViewFlipper来实现下splash引导页的效果;
在xml布局文件中可以直接将splash显示的图片通过ImageView放在ViewFlipper中,当然也可以通过代码的方式创建,然后通过addView方法添加到对应的布局中;



    
        
        
        
        
            
            

不过就这样子的话还不能进行滑动,需要通过GestureDetector这个类来处理手势滑动,在activity中重写onTouchEvent方法,在用户按下或者触摸是,将手势处理交给GestureDetector类中的方法去处理;

  @Override
    public boolean onTouchEvent(MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

在用户触摸时就会回调onFling方法;

  @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        if (e1.getX() > e2.getX()) {
            if (index >= childCount - 1) {
                return false;
            }
            viewFlipper.showNext();
            index = index + 1;
        } else if (e1.getX() < e2.getX()) {
            if (index <= 0) {
                return false;
            }
            viewFlipper.showPrevious();
            index = index - 1;
        } else {
            return false;
        }
        changeInicator();
        return false;
    }

通过showNext和showPrevious方法来切换下一页和上一页,然后去改变指示器的效果,这样效果就实现了;
完整代码:

public class ViewFillipperActivity extends AppCompatActivity implements GestureDetector.OnGestureListener {
    private ViewFlipper viewFlipper;
    private Button btn;
    private LinearLayout linearLayout;
    private GestureDetector gestureDetector;
    private int index = 0;//当前是第几屏
    private int childCount;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.acvitivty_viewfillipper);
        viewFlipper = findViewById(R.id.viewflipper);
        btn = findViewById(R.id.id_btn);
        linearLayout = findViewById(R.id.id_indicator);
        childCount = viewFlipper.getChildCount();
        initIndicator();

        gestureDetector = new GestureDetector(this);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(ViewFillipperActivity.this, MainActivity.class));
                finish();
            }
        });
    }

    /**
     * 初始化指示器
     */
    private void initIndicator() {

        int width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f, getResources().getDisplayMetrics());
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(width, width);
        for (int i = 0; i < childCount; i++) {
            View view = new View(this);
            view.setBackgroundResource(i == 0 ? R.drawable.dot_select : R.drawable.dot_normal);
            lp.rightMargin = 2 * width;
            view.setId(i);
            view.setLayoutParams(lp);
            linearLayout.addView(view);
        }
    }

    @Override
    public boolean onDown(MotionEvent e) {
        return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {

    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        if (e1.getX() > e2.getX()) {
            if (index >= childCount - 1) {
                return false;
            }
            viewFlipper.showNext();
            index = index + 1;
        } else if (e1.getX() < e2.getX()) {
            if (index <= 0) {
                return false;
            }
            viewFlipper.showPrevious();
            index = index - 1;
        } else {
            return false;
        }
        changeInicator();
        return false;
    }

    private void changeInicator() {
        for (int i = 0; i < childCount; i++) {
            View childAt = linearLayout.getChildAt(i);
            childAt.setBackgroundResource(i == index ? R.drawable.dot_select : R.drawable.dot_normal);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }
}
android splash引导页的实现_第2张图片
GIF.gif

不过ViewFlipper在切换的时候页面ViewPager的那种切换过渡动画效果,还有通过监听HorizontalScrollView的横向滚动也可以实现该效果,方式很多种,具体的可以根据项目的需要选择最适合的方式来实现。

下面就是一个splash视频的效果,splash的切换的还是采用上面写好的SplashLayout类,主要是处理fragment里面的视频播放逻辑;

public class VideoFragment extends Fragment implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener {
    private static final String VIDEO_RES = "res";
    private static final String SHOW_WELCOME = "show_welcome";
    private FullScreenVideoView videoView;
    private ImageView geNext;
    //是否显示按钮
    private boolean showWelcome;

    public static VideoFragment getInstance(int resId, boolean showWelcome) {
        VideoFragment fragment = new VideoFragment();
        Bundle bundle = new Bundle();
        bundle.putInt(VIDEO_RES, resId);
        bundle.putBoolean(SHOW_WELCOME, showWelcome);
        fragment.setArguments(bundle);
        return fragment;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_video_guide, container, false);
        videoView = view.findViewById(R.id.videoview_guide);
        int videoRes = getArguments().getInt(VIDEO_RES);
        showWelcome = getArguments().getBoolean(SHOW_WELCOME);
        geNext = view.findViewById(R.id.go_next);
        geNext.setVisibility(showWelcome ? View.VISIBLE : View.INVISIBLE);

        videoView.setVideoPath("android.resource://" + getActivity().getPackageName() + "/" + videoRes);
        initEvent();
        return view;
    }

    private void initEvent() {
        videoView.setOnPreparedListener(this);
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        //准备播放回调
        if (videoView != null) {
            videoView.requestFocus();
            videoView.seekTo(0);
            videoView.start();
            videoView.setOnCompletionListener(this);
        }
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        //播放完成监听
        videoView.requestFocus();
        videoView.seekTo(0);
        videoView.start();

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (videoView != null) {
            videoView.stopPlayback();
        }
    }
}

GIF.gif

源码地址

你可能感兴趣的:(android splash引导页的实现)