ViewPager+圆形指示器实现左右滑动的导航欢迎页
Posted LQS_Android
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ViewPager+圆形指示器实现左右滑动的导航欢迎页相关的知识,希望对你有一定的参考价值。
预览效果如下:
代码实现如下:
第一步:MainActivity中添加一个跳转导航页的按钮,布局文件activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center"
tools:context=".MainActivity">
<Button
android:id="@+id/jump_guide_activity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="新手引导页" />
</LinearLayout>
MainActivity.java代码:
package com.xw.guidepagedemo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button mJumpGuidePage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initview();
initListener();
}
private void initview() {
//跳转导航页的按钮
mJumpGuidePage = findViewById(R.id.jump_guide_activity);
}
private void initListener() {
//跳转导航页的按钮的点击事件
mJumpGuidePage.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(this,GuidePageActivity.class);
startActivity(intent);
}
}
第二步:创建导航页的Activity:GuidePageActivity.class和布局文件activity_page_guide.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
tools:context=".GuidePageActivity">
<androidx.viewpager.widget.ViewPager
android:id="@+id/guide_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="50dp"
>
<!-- 用于动态添加shape圆形灰色小圆点的指示器的布局 -->
<LinearLayout
android:id="@+id/indicator_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
</LinearLayout>
<!-- 用于遮盖在灰色小圆点上面的红色小圆点 -->
<ImageView
android:id="@+id/red_dot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/shape_circle_selected"
/>
</RelativeLayout>
</RelativeLayout>
上面的布局文件中,通过相对布局的进行组件的布局,在ViewPager组件上添加一个相对布局的指示器容器,指示器容器中包含一个用于动态添加shape圆形灰色小圆点的线性布局和一个ImageView组件,这个ImageView组件默认和第一个小灰点重合。
其中小灰点、小红点是通过shape类型的资源定义的:
小灰点:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size
android:width="12dp"
android:height="12dp"/>
<solid android:color="#5000"/>
</shape>
小红点:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size
android:width="12dp"
android:height="12dp"/>
<solid android:color="#f00"/>
</shape>
核心代码在GuidePageActivity.class中:
package com.xw.guidepagedemo;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.xw.guidepagedemo.adapter.GuideViewPagerAdapter;
import java.util.ArrayList;
public class GuidePageActivity extends AppCompatActivity {
private ViewPager mViewpager;
private int[] mImageIds={R.drawable.ic_img1,R.drawable.ic_img2,R.drawable.ic_img3,R.drawable.ic_img4};
private ArrayList<ImageView> mImageViewList;
private LinearLayout mIndicatorContainer;
private ImageView mRedDot;
private int mPointWidth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.activity_guide_page);
initView();
}
private void initView() {
mViewpager = findViewById(R.id.guide_viewpager);
//指示器:底部灰色小圆点的布局容器
mIndicatorContainer = findViewById(R.id.indicator_container);
//使用相对布局,小灰点上层小红点
mRedDot = findViewById(R.id.red_dot);
//初始化引导页大图片
initGuideImage();
//初始化指示器的小灰点
initIndicatorGrayDot();
GuideViewPagerAdapter guideViewPagerAdapter = new GuideViewPagerAdapter(getApplicationContext(),mImageViewList);
mViewpager.setAdapter(guideViewPagerAdapter);
/**
* 这里需要计算两个灰色小圆点的距离,使得小红点随着ViewPager页面滑动时也跟着移动位置
* 小红点移动距离计算公式:页面移动的百分比positionOffset * 两个灰色小圆点的间距length
*/
mViewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
/**
* 页面滑动时的回调
* @param position 当前页面位置索引
* @param positionOffset :页面滑动偏移的百分比:0.0-1.0,特点:向右滑到新的一页时,滑动偏移的百分比到达1后,置零,从零重新开始计算新的一页的滑动偏移的百分比
* @param positionOffsetPixels 页面滑动偏移的像素
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
Log.d("TAG","当前位置:"+position+";当前页面滑动的百分比:"+positionOffset);
/**
* 计算小红点移动时的左边距:通过视图树监听中计算出来的两个小灰点之间的间距✖页面滑动偏移的百分比=mPointWidth*positionOffset
* 由于页面滑动百分比的计算特点可知,当小红点滑到新的一页后继续滑动时,当前左边距需要累加前position个页的mPointWidth宽度
*/
int leftMargin = (int) (mPointWidth*positionOffset+position*mPointWidth);
//获取小红点的左边距属性,修改赋值
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)mRedDot.getLayoutParams();
params.leftMargin = leftMargin;
//将布局参数设置给视图(小红点)
mRedDot.setLayoutParams(params);
}
/**
* 页面选中时的回调
* @param position
*/
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
/**
* 通过视图树监听计算小灰点之间的间距:视图View在绘制方法layout()执行结束之后,布局的位置、边距大小、尺寸才能确定
*/
mRedDot.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//第二个小圆点距离左侧屏幕的距离
int secondGrayDotLeft = mIndicatorContainer.getChildAt(1).getLeft();
//第一个小圆点距离左侧屏幕的距离
int firstGrayDotLeft = mIndicatorContainer.getChildAt(0).getLeft();
//两个小圆点之间的间距
mPointWidth = secondGrayDotLeft-firstGrayDotLeft;
Log.d("TAG","两个小圆点之间的间距:"+ mPointWidth);
//为了避免这个视图树观察者频繁监听 所以最后需要移除一下监听对象
mRedDot.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
public void initGuideImage(){
mImageViewList = new ArrayList<>();
for (int i=0;i<mImageIds.length;i++){
ImageView imageView = new ImageView(this);
imageView.setBackgroundResource(mImageIds[i]);
mImageViewList.add(imageView);
}
}
//初始化指示器底部默认的灰色圆点:未滑到、选中该页
public void initIndicatorGrayDot(){
for (int i=0;i<mImageIds.length;i++){
ImageView pointView = new ImageView(this);
pointView.setBackgroundResource(R.drawable.shape_circle_default);
//设置布局参数
LinearLayout.LayoutParams params =new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
if (i>0){
//从第二个圆点开始设置左边距为10
params.leftMargin=10;
}
pointView.setLayoutParams(params);
mIndicatorContainer.addView(pointView);
}
}
}
上面的代码绘制步骤是:
①先绘制4张大的导航图
②再根据导航图的数量绘制对应几个指示器的小灰点(四张图就绘制4个小灰点)
③再绘制小红点,小红点默认覆盖在第一个小灰点上
④通过视图树监听layout()布局完成,计算两个小灰点之间的距离
⑤根据ViewPager的滑动监听器获取到页面的滑动百分比,结合第④步计算小红点随页面滑动的距离
⑥获取小红点左侧边距的属性,对小红点左边距动态赋值,实现小红点随页面滑动二移动。
一些公式都在注释中,仔细琢磨可以看懂,很简单。
其中,ViewPager的适配器GuideViewPagerAdapter.class如下:
package com.xw.guidepagedemo.adapter;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
import java.util.ArrayList;
/**
* Copyright (c)2021 网络科技有限公司
*
* @author: LQS
* @date: 2021/7/2
* @description:
*/
public class GuideViewPagerAdapter extends PagerAdapter {
private ArrayList<ImageView> mImageViewList;
private Context mContext;
public GuideViewPagerAdapter(Context context, ArrayList<ImageView> imageList) {
mImageViewList = imageList;
mContext = context;
}
@Override
public int getCount() {
return mImageViewList.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
//加载引导页大图片
container.addView(mImageViewList.get(position));
return mImageViewList.get(position);
// //加载指定的布局文件
// View view = View.inflate(mContext, R.layout.friend_gift_item, null);
// ImageView giftsImage =view.findViewById(R.id.gift_img);
// giftsImage.setImageResource(mImageIDs[position]);
// TextView detailBtn = view.findViewById(R.id.btn_detail);
// detailBtn.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// Intent intent = new Intent();
// intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
// intent.setClass(mContext, GiftDetailActivity.class);
// mContext.startActivity(intent);
// }
// });
// container.addView(view);
// return view;
}
/**
* 该方法一定要重写,从container中移除上一个ImageView对象,否则报错
*
* @param container
* @param position
* @param object
*/
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView((View) object);
}
}
效果图见上,到此完结!
遇见即是缘分,欢迎评论、点赞、关注!
以上是关于ViewPager+圆形指示器实现左右滑动的导航欢迎页的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin 实现可点击可滑动顶部导航栏(AppBarLayout+TabLayout)和左右切换可滑动页面(ViewPager)的功能
在PopWindow弹窗中使用ViewPager复杂布局+圆形指示器
Android- fragment结合ViewPager实现左右滑动