ViewPager切换页面——学习笔记

这篇博客介绍了如何使用ViewPager创建应用的引导页面,包括设置ViewPager的滑动效果,实现按钮和小红点的交互。通过创建LinearLayout和ImageView展示小点,利用OnPageChangeListener监听页面切换并实现小红点的移动动画。此外,还涉及到布局文件的编写和资源文件的选择器设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大部分应用在安装后刚打开都有个引导页面,一般需要把这些引导页面滑到最后才能进入主界面。
同时引导页面上一般都有几个点,分别对应每个ViewPager,接下来就是关于如何实现这一功能的学习笔记。
这里写图片描述
这张是网上随便找的一个图片,差不多就是实现这样的界面。

整体思路:这个页面的布局由几个部分组成
①:ViewPager组成滑动的每一页。
②:一个按钮,用来进入主界面,只在ViewPager的最后一面显示。
③:位于按钮附近的几个小点,对应于每一页ViewPager。这一部分通过LinearLayout+ImageView组成,如果拿上图做参考的话,LinearLayout里面实现四个透明的小点,就是一个pointgroup,ImageView里面实现那个白色的小点。

接下来开始按照步骤分别实现:
1.首先设置一下整体布局——
在RelativeLayout里面实现整个引导页面的布局,以下是布局页面代码

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <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:background="@drawable/btn_start_main_selector"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="80dp"
        android:layout_alignParentBottom="true"
        android:paddingLeft="20dp"
        android:paddingRight="20dp"
        android:textColor="@drawable/btn_start_main_text_selector"
        android:text="立即体验"
        android:textSize="20sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

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

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

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

    </RelativeLayout>


</RelativeLayout>

以上代码中,有
①:android:background=”@drawable/btn_start_main_selector”
②:android:textColor=”@drawable/btn_start_main_text_selector”、
③:android:background=”@drawable/point_red”
需要实现,这三者分别表示按钮的背景颜色、按钮的文字颜色、与页面相对应的小点的颜色(下面称这个点是小红点),接下来分别实现(实现的快捷方式是依次点中这三条属性然后依次按Alt + Enter键,来在drawable里面创建xml文件)。

①:btn_start_main_selector——

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="false" android:drawable="@drawable/button_red_normal"/>
    <item android:state_pressed="true" android:drawable="@drawable/button_red_pressed"/>
</selector>

android:state_pressed用来表示按钮是否按下这个状态,true表示按下,false表示未按下。其中@drawable/button_red_normal和@drawable/button_red_pressed分别是按钮按下前和按下后的表示不同状态的图片。

②:btn_start_main_text_selector——

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="false" android:color="@android:color/white"/>
    <item android:state_pressed="true" android:color="@android:color/black"/>
</selector>

这个是表示按下前后按钮内文字的颜色变化,文字的颜色是不能用图片去表示的,所以用属性表示。

③:drawable/point_red——

<?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"/>
    <solid android:color="@android:color/holo_red_light"/>

</shape>

这里使用的是shape,表示设置小点的形状,android:shape=”oval”代表设置为圆形。

2.实现LinearLayout的三个小点:
先在GuideActivity中创建各个控件的实例,然后实现三个小点,
具体方法是创建三个ImageView实例,然后通过setBackgroundResource()对其设置点的布局,最后通过LinearLayout.LayoutParams()方法设置具体参数以决定点的大小。
将三个点设置完后,在通过ViewPager来实现页面的切换,完整代码如下


public class GuideActivity extends AppCompatActivity {
    private static final String TAG = GuideActivity.class.getSimpleName();
    private ViewPager viewpager;
    private Button btn_start_main;
    private LinearLayout ll_point_group;
    private ImageView iv_red_point;

    private ArrayList<ImageView> imageViews;
    private int leftmax; //两点的间距
    private  int widthdpi;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_guide);
        viewpager = (ViewPager) findViewById(R.id.viewpager);
        btn_start_main= (Button) findViewById(R.id.btn_start_main);
        ll_point_group = (LinearLayout) findViewById(R.id.ll_point_group);
        iv_red_point = (ImageView) findViewById(R.id.iv_red_point);

        //准备数据
        int[] ids = new int[]{
                R.drawable.guide_1,
                R.drawable.guide_2,
                R.drawable.guide_3
        };
        widthdpi = DensityUtil.dip2px(this, 10);
        Log.e(TAG, widthdpi + "-------------");

        imageViews = new ArrayList<>();
        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, widthdpi);
            if (i != 0){
                //不包括第0个,所有的点距离左边10个像素
                params.leftMargin = widthdpi;
            }
            point.setLayoutParams(params);
            //把点添加到线形布局中
            ll_point_group.addView(point);
        }

        //设置ViewPager的适配器
        viewpager.setAdapter(new MyPagerAdapter());

        //根据View的生命周期,当视图执行到onLayout和onDraw的时候,视图的高和宽、边距都有了
        //getViewTreeObserver方法是获取视图树的观察者,然后添加监听
        iv_red_point.getViewTreeObserver().addOnGlobalLayoutListener(new MyOnGlobalLayoutListener());

        //添加监听,用于得到屏幕滑动的百分百比
        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);
            // Log.e(TAG, "position是 " + position + ",positionOffset是 " + positionOffset + ",positionOffsetPixels是 " + positionOffsetPixels);
            //两点间滑动的距离对应的坐标 = 原来的起始位置 + 两点间移动的距离
            int 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{
        @Override
        public void onGlobalLayout() {
            //执行不止一次
            iv_red_point.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            //第1个点到第0个点的间距:第一个点到左边的距离 - 第0个点到左边的距离
            leftmax = ll_point_group.getChildAt(1).getLeft() - ll_point_group.getChildAt(0).getLeft();
            Log.e(TAG, "leftmax是 " + leftmax);
        }
    }

    //设置ViewPager的适配器
    class MyPagerAdapter extends PagerAdapter{

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

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

        /**
         * 作用是getView
         * @param container ViewPager
         * @param position 要创建页面的位置
         * @return 返回和创建当前页面的有关系值
         */
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ImageView imageView = imageViews.get(position);
            container.addView(imageView);

            return imageView;
            //return position;
        }

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

}

上述代码中,用到了一个DensityUtil.dip2px()方法,这个方法用于将手机的从 dip 的单位 转成为 px(像素),如果没有这个方法,最后三个点在不同分辨率手机下的实际大小是不一样,具体实现方法是在创建一个utils包,然后创建DensityUtil类,代码如下

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);
    }
}

DensityUtil类实现完后再来看GuideActivity的代码,里面使用ViewPager时,还需要需要创建VIewPager的适配器,适配器里面要重写四个方法,这些都比较简单,主要是如何去实现小红点的移动动画。
实现小红点的移动,需要知道小点的移动距离,然后还要设置所在的坐标,这些需要借助ViewPager.OnPageChangeListener监听器和ViewTreeObserver.OnGlobalLayoutListener解调器来实现,详细情况看代码说明。

最后补充一个point_normal.xml文件,忘记加上去了:

<?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"/>
    <solid android:color="@android:color/darker_gray"/>

</shape>

以下是结果图
这里写图片描述

蛤蛤蛤,这三张是从网上找的图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值