android欢迎引导页面

本文介绍了一种实现APP引导页中红点跟随页面滑动的方法,通过计算红点移动距离并更新其位置,使红点能在多个引导页间平滑过渡。

现在主流的APP开启都会有一个欢迎引导页,所以收藏一个引导页的开发方法是必要的。
先上效果图:效果图
完整工程代码下载地址:代码下载地址
分析:这里主要的难点是红点的移动原理,所以就分析红点的移动原理。
红点移动原理
利用距离左边的距离实现红点的移动
params.leftMargin = 动态值
屏幕滑动的距离:屏幕宽 = 屏幕滑动的百分比
两点间移动的距离:间距 = 屏幕滑动的距离:屏幕宽 = 屏幕滑动的百分比(已知)
两点间移动的距离 = 屏幕滑动百分比*间距
两点间滑动距离对应的坐标 = 原来的起始坐标位置+两点间移动的距离
params.leftMargin = 两点间滑动距离对应的坐标
间距 = 第1个点距离左边的距离 - 第0个点距离左边的距离

因为点要浮在视图上面,所以这里我们的父视图选择用相对布局RelativeLayout,在布局中先添加一个线性布局用于动态的添加点。
布局中有一个viewpager容器,保存滑动页面。首先,我们先把ViewPager先实现,他的主要作用是保存滑动引导页面,实现ViewPager分两个步骤:
一、准备数据,把要显示的图片id保存在一个数组中
//准备数据

 int ids[] = new int[]{R.mipmap.guide_1,R.mipmap.guide_2,R.mipmap.guide_3};

新建一个集合保存要显示的这几张图片,同时新建引导点数的点,把点添加到我们事先准备好的LinearLayout线性布局中。同时我们也设置了点的间距,需要注意的是,这里我们应用了像素转换工具类,把dp转换为px,这个的作用是为了做适配不同手机用的。

private ArrayList<ImageView> imageViews;
     for (int i=0;i<ids.length;i++){
            ImageView imageView = new ImageView(this);
            //设置背景
            imageView.setBackgroundResource(ids[i]);
            //添加到图片集合中
            imageViews.add(imageView);

            //创建点--有多少张图片要显示就有多少个点
            ImageView point = new ImageView(this);
            point.setBackgroundResource(R.drawable.point_normal);
            /**
             * 单位是像素
             * 把单位当成dp转成对应的像素
             */

            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(widthdpi,heightdpi);
            if (i!=0){
                //不包括第0个,所有的点距离设置为10个像素
                params.leftMargin = widthdpi;
            }
            point.setLayoutParams(params);
            //把点添加到点集合中
            ll_point_group.addView(point);

        }

/**
 * 单位转换工具
 * dp与px的互相转换
 * Created by willkong on 2016/11/3.
 */

public class DensityUtil {
    /**
     * 根据手机的分辨率从 dip 的单位 转成为 px(像素)
     */
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }
}

创建灰色和红色两个圆点

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
    <size android:height="10dp" android:width="10dp"></size>
    <solid android:color="@android:color/darker_gray"></solid>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
    <size android:height="10dp" android:width="10dp"></size>
    <solid android:color="@android:color/holo_red_dark"></solid>
</shape>

二、给ViewPager设置适配器

 class MyPagerAdapter extends PagerAdapter{

        /**
         * 返回数据的总个数
         * @return
         */
        @Override
        public int getCount() {
            return imageViews.size();
        }

        /**
         * 作用,getView
         * @param container viewpager
         * @param position 要创建页面的位置
         * @return
         */
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ImageView imageView = imageViews.get(position);
            //添加到容器中
            container.addView(imageView);
//            return position;
            return imageView;
        }

        /**
         * 判断
         * @param view 当前创建的视图
         * @param object 上面instantiateItem返回的结果值
         * @return
         */
        @Override
        public boolean isViewFromObject(View view, Object object) {
//            return view == imageViews.get(Integer.parseInt((String) object));
            return view ==  object;
        }


        /**
         * 销毁页面
         * @param container viewpager
         * @param position 要销毁页面的位置
         * @param object 要销毁的视图
         */
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
//            super.destroyItem(container, position, object);
            container.removeView((View) object);
        }

    }

上面的代码已经实现了视图的滑动和底下的灰色的圆点引导点,下面我们要实现一个根据页面移动的红点,所以在布局中添加一个红点覆盖在灰色圆点的上面。
activity_guide_pager.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_guide"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.mynews.activity.GuideActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <Button
        android:id="@+id/btn_start_main"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="80dp"
        android:background="@drawable/btn_start_main_selector"
        android:paddingLeft="20dp"
        android:paddingRight="20dp"
        android:text="开始体验"
        android:textColor="@drawable/btn_start_main_textcolor_selector"
        android:textSize="20sp"
        android:visibility="gone" />

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="40dp">

        <LinearLayout
            android:id="@+id/ll_point_group"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal" />

        <ImageView
            android:id="@+id/iv_red_point"
            android:layout_width="10dp"
            android:layout_height="10dp"
            android:background="@drawable/point_red" />
    </RelativeLayout>


</RelativeLayout>

到这里视图就完成了,下面就要实现红点根据视图滑动而移动。根据上面的红点移动原理来实现红点的移动。
一、根据View的生命周期,当视图执行到onLayout或者onDraw的时候,视图的高和宽,边距都有了
所以先得到红点的视图树的监听者

iv_red_point.getViewTreeObserver().addOnGlobalLayoutListener(new MyOnGlobalLayoutListener());
class MyOnGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener{

        @Override
        public void onGlobalLayout() {
            //执行不止一次,视图树包含了所有的视图,所以执行不止一次
            iv_red_point.getViewTreeObserver().removeGlobalOnLayoutListener(this);

            //间距 = 第一个点距离左边的距离 - 第0个点距离左边的距离
            leftmax = ll_point_group.getChildAt(1).getLeft() - ll_point_group.getChildAt(0).getLeft();
        }
    }

这里就得到了两点间的间距。
下面就是得到ViewPager屏幕滑动的百分比,所以就要监听ViewPager的滑动得到他滑动的百分比。

viewpager.addOnPageChangeListener(new MyOnPageChangeListener());
class MyOnPageChangeListener implements ViewPager.OnPageChangeListener{

        /**
         * 当页面滚动了回调这个方法
         * @param position 当前滑动页面的位置
         * @param positionOffset 页面滑动的百分比
         * @param positionOffsetPixels 页面滑动的像素
         */
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            //两点间移动的距离 =  屏幕百分比 * 间距
            int leftmargin = (int) (positionOffset * leftmax);
            //两点间滑动对应的坐标 = 原来的起始位置 + 两点间移动的距离
            leftmargin = (int) (position * leftmax + positionOffset * leftmax);
            //params.LeftMargin = 两点间滑动对应的坐标
            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) iv_red_point.getLayoutParams();
            params.leftMargin = leftmargin;
            iv_red_point.setLayoutParams(params);
        }

        /**
         * 当页面被选中的时候,回调这个方法
         * @param position 被选中页面的对应位置
         */
        @Override
        public void onPageSelected(int position) {
            if (position == imageViews.size()-1){
                //最后一个页面
                btn_start_main.setVisibility(View.VISIBLE);
            }else {
                //其他页面
                btn_start_main.setVisibility(View.GONE);
            }
        }

        /**
         * 当ViewPager页面滑动状态发生变化的时候会回调这个方法
         * @param state
         */
        @Override
        public void onPageScrollStateChanged(int state) {

        }
    }

GuiderPager.Java


import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.navigationpage.utils.DensityUtil;

import java.util.ArrayList;

import static com.navigationpage.R.id.viewpager;

public class GuidePager extends AppCompatActivity {
    private Button btn_start_main;
    private ViewPager viewpager;
    private LinearLayout ll_point_group;
    private ImageView iv_red_point;
    private ArrayList<ImageView> imageViews;
    private int leftmax;//点的间距
    private int widthdpi;
    private int heightdpi;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_guide_pager);
        initView();
        initData();
    }

    private void initData() {
        //准备数据
        int ids[] = new int[]{R.mipmap.guide_1,R.mipmap.guide_2,R.mipmap.guide_3};
        //创建要显示的图片控件
        imageViews = new ArrayList<>();
        widthdpi = DensityUtil.dip2px(this,10);
        heightdpi = DensityUtil.dip2px(this,10);
        for (int i=0;i<ids.length;i++){
            ImageView imageView = new ImageView(this);
            //设置背景
            imageView.setBackgroundResource(ids[i]);
            //添加到图片集合中
            imageViews.add(imageView);

            //创建点--有多少张图片要显示就有多少个点
            ImageView point = new ImageView(this);
            point.setBackgroundResource(R.drawable.point_normal);
            /**
             * 单位是像素
             * 把单位当成dp转成对应的像素
             */

            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(widthdpi,heightdpi);
            if (i!=0){
                //不包括第0个,所有的点距离设置为10个像素
                params.leftMargin = widthdpi;
            }
            point.setLayoutParams(params);
            //把点添加到点集合中
            ll_point_group.addView(point);

        }

        //设置ViewPager的适配器
        viewpager.setAdapter(new MyPagerAdapter());
        //根据View的生命周期,当视图执行到onLayout或者onDraw的时候,视图的高和宽,边距都有了,这里就得到两个点之间的间距了
        iv_red_point.getViewTreeObserver().addOnGlobalLayoutListener(new MyOnGlobalLayoutListener());
        //获取ViewPager屏幕滑动的百分比
        viewpager.addOnPageChangeListener(new MyOnPageChangeListener());
    }

    class MyOnPageChangeListener implements ViewPager.OnPageChangeListener{

        /**
         * 当页面滚动了回调这个方法
         * @param position 当前滑动页面的位置
         * @param positionOffset 页面滑动的百分比
         * @param positionOffsetPixels 页面滑动的像素
         */
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
        {
            //两点间移动的距离 =  屏幕百分比 * 间距
            int leftmargin = (int) (positionOffset * leftmax);
            //两点间滑动对应的坐标 = 原来的起始位置 + 两点间移动的距离
            leftmargin = (int) (position * leftmax + positionOffset * leftmax);
            //params.LeftMargin = 两点间滑动对应的坐标
            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)
                    iv_red_point.getLayoutParams();
            params.leftMargin = leftmargin;
            iv_red_point.setLayoutParams(params);
        }

        /**
         * 当页面被选中的时候,回调这个方法
         * @param position 被选中页面的对应位置
         */
        @Override
        public void onPageSelected(int position) {
            if (position == imageViews.size()-1){
                //最后一个页面
                btn_start_main.setVisibility(View.VISIBLE);
            }else {
                //其他页面
                btn_start_main.setVisibility(View.GONE);
            }
        }

        /**
         * 当ViewPager页面滑动状态发生变化的时候会回调这个方法
         * @param state
         */
        @Override
        public void onPageScrollStateChanged(int state) {

        }
    }

    class MyOnGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener{

        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        @Override
        public void onGlobalLayout() {
            //执行不止一次
            iv_red_point.getViewTreeObserver().removeOnGlobalLayoutListener(this);

            //间距 = 第一个点距离左边的距离 - 第0个点距离左边的距离
            leftmax = ll_point_group.getChildAt(1).getLeft() - ll_point_group.getChildAt(0).getLeft();
        }
    }

    class  MyPagerAdapter extends PagerAdapter{

        public MyPagerAdapter() {
            super();
        }

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

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ImageView imageView = imageViews.get(position);
            //添加到容器中
            container.addView(imageView);
            return imageView;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }
    }

    private void initView() {
        btn_start_main = (Button) findViewById(R.id.btn_start_main);
        viewpager = (ViewPager) findViewById(R.id.viewpager);
        ll_point_group = (LinearLayout) findViewById(R.id.ll_point_group);
        iv_red_point = (ImageView) findViewById(R.id.iv_red_point);
    }
}

到这里就把欢迎引导页面实现了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值