Android仿IOS ViewPager滑动进度条

作者:shineflowers 时间:2022-10-31 08:27:38 

最近做项目,碰到如下的需求:ViewPager分页,如果是6页(包括6页)就用圆点,如果是6页以上就用进度条来切换。前面一种交互方法最常见,用小圆点来表示当前选中的页面,这些小圆点称为导航点,很多App都是这种实现方式。当用户第一次安装或升级应用时,都会利用导航页面告诉用户当前版本的主要亮点,一般情况下当行页面有三部分组成,背景图片,导航文字和滑动的原点,即下面的效果:

Android仿IOS ViewPager滑动进度条

这里就不作详细的讲解,大家可以参考我以前写过的博客:
ViewPager实现图片轮翻效果
今天来实现ViewPager进度条切换,主要逻辑如下:
MainActivity.java


package com.jackie.slidebarviewdemo.activity;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import com.jackie.slidebarviewdemo.R;
import com.jackie.slidebarviewdemo.widget.SlideBarView;

public class MainActivity extends AppCompatActivity {
 private SlideBarView mSlideBarView;
 private TextView mTextView;

@Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

mSlideBarView = (SlideBarView) findViewById(R.id.slide_bar);
   mTextView = (TextView) findViewById(R.id.text_view);

mSlideBarView.setTotalPage(80);
   mSlideBarView.setOnSlideChangeListener(new SlideBarView.OnSlideChangeListener() {
     @Override
     public void onSlideChange(int page) {
       mTextView.setText("当前是第" + page + "页");
     }
   });
 }
}

SlideBarView.java


package com.jackie.slidebarviewdemo.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.jackie.slidebarviewdemo.R;
import com.jackie.slidebarviewdemo.utils.ConvertUtils;

/**
* Created by Jackie on 2017/1/17.
*/

public class SlideBarView extends RelativeLayout {
 private LayoutInflater mInflater;

private RelativeLayout mSlideBarView;
 private View mSlideBarBlock;

private PopupWindow mPopupWindow;
 private TextView mPopupText;

private int mDp40;

private String mBound = "no"; // no表示没到边界,left为到左边界了,right表示到右边界了

public interface OnSlideChangeListener {
   void onSlideChange(int page);
 }

private OnSlideChangeListener mOnSlideChangeListener;
 public void setOnSlideChangeListener(OnSlideChangeListener onSlideChangeListener) {
   this.mOnSlideChangeListener = onSlideChangeListener;
 }

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

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

public SlideBarView(Context context, AttributeSet attrs, int defStyleAttr) {
   super(context, attrs, defStyleAttr);

init(context);
   initEvent();
 }

private void init(Context context) {
   mInflater = LayoutInflater.from(context);
   View slideBar = mInflater.inflate(R.layout.slide_bar, null);
   LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
   addView(slideBar, params);

mSlideBarView = (RelativeLayout) slideBar.findViewById(R.id.slide_bar_view);
   mSlideBarBlock = slideBar.findViewById(R.id.slide_bar_block);

mDp40 = ConvertUtils.dip2px(context, 40);
 }

private void initEvent() {
   mSlideBarView.setOnTouchListener(new OnTouchListener() {
     int currentX = 0;
     int startX = 0;

@Override
     public boolean onTouch(View v, MotionEvent event) {
       switch (event.getAction()) {
         case MotionEvent.ACTION_DOWN:
           currentX = (int) event.getX();
           startX = (int) event.getX();

// 设置滑块的滑动, 手指第一次点下去把滑块放到手指上
           int downLeft = currentX - mSlideBarBlock.getMeasuredWidth() / 2;
           int downTop = mSlideBarBlock.getTop();
           int downRight = downLeft + mSlideBarBlock.getWidth();
           int downBottom = mSlideBarBlock.getBottom();

//边界检测
           if (downLeft < 0) {
             downLeft = 0;
             downRight = mSlideBarBlock.getMeasuredWidth();
           } else if (downRight > mSlideBarView.getMeasuredWidth()) {
             downLeft = mSlideBarView.getMeasuredWidth() - mSlideBarBlock.getMeasuredWidth();
             downRight = mSlideBarView.getMeasuredWidth();
           }

mSlideBarBlock.layout(downLeft, downTop, downRight, downBottom);
           break;
         case MotionEvent.ACTION_MOVE:
           currentX = (int) event.getX();
           int currentPage = currentX * mTotalPage / mSlideBarView.getMeasuredWidth();
           if (currentPage < 0) {
             currentPage = 0;
           } else if (currentPage > mTotalPage) {
             currentPage = mTotalPage;
           }

// 设置滑块的滑动
           int moveLeft = currentX - mSlideBarBlock.getMeasuredWidth() / 2;
           int moveTop = mSlideBarBlock.getTop();
           int moveRight = moveLeft + mSlideBarBlock.getMeasuredWidth();
           int moveBottom = mSlideBarBlock.getBottom();

//边界处理
           if (moveLeft < 0) {
             mBound = "left";

moveLeft = 0;
             moveRight = mSlideBarBlock.getMeasuredWidth();
           } else if (moveRight >= mSlideBarView.getMeasuredWidth()) {
             mBound = "right";

moveLeft = mSlideBarView.getMeasuredWidth() - mSlideBarBlock.getMeasuredWidth();
             moveRight = mSlideBarView.getMeasuredWidth();
           } else {
             mBound = "no";
           }

mSlideBarBlock.layout(moveLeft, moveTop, moveRight, moveBottom);
           startX = currentX;

//设置popupWindow的弹出位置
           if (mOnSlideChangeListener != null) {
             if (currentPage == mTotalPage) {
               //防止ViewPager越界
               currentPage = mTotalPage - 1;
             }

mOnSlideChangeListener.onSlideChange(currentPage);

if (mPopupWindow != null) {
               mPopupText.setText(currentPage + "");

//设置PopupWindow的滑动
               if (!mPopupWindow.isShowing()) {
                 int[] location = new int[2];
                 mSlideBarView.getLocationInWindow(location);
                 mPopupWindow.showAsDropDown(mSlideBarView, currentX, location[1] - mDp40);
               } else {
                 if ("no".equals(mBound)) {
                   int[] location = new int[2] ;
                   mSlideBarView.getLocationInWindow(location);
                   mPopupWindow.update(currentX, location[1] - mDp40, mPopupWindow.getWidth(), mPopupWindow.getHeight(), true);
                 }
               }
             }
           }
           break;
         case MotionEvent.ACTION_UP:
           currentX = 0;
           startX = 0;
           mPopupWindow.dismiss();
           break;
       }

return true;
     }
   });

// 初始化PopupWindow
   View contentView = mInflater.inflate(R.layout.popup_window, null);
   mPopupText = (TextView) contentView.findViewById(R.id.popup_text);
   mPopupWindow = new PopupWindow(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
   mPopupWindow.setContentView(contentView);
   mPopupWindow.setOutsideTouchable(true);
   mPopupWindow.setBackgroundDrawable(getResources().getDrawable(R.mipmap.popup_window_bg));
   mPopupWindow.setAnimationStyle(0);
 }

int mTotalPage = 0;
 public void setTotalPage(int totalPage) {
   this.mTotalPage = totalPage;
 }
}

相关的单位转化工具,大家可以拷贝到自己的项目中直接使用。
ConvertUtils.java


package com.jackie.slidebarviewdemo.utils;

import android.content.Context;

public class ConvertUtils {
 public static int dip2px(Context context, float dpValue) {
   final float scale = context.getResources().getDisplayMetrics().density;
   return (int) (dpValue * scale + 0.5f);
 }

public static int px2dip(Context context, float pxValue) {
   final float scale = context.getResources().getDisplayMetrics().density;
   return (int) (pxValue / scale + 0.5f);
 }

public static int px2sp(Context context, float pxValue) {
   final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;  
   return (int) (pxValue / fontScale + 0.5f);  
 }  

public static int sp2px(Context context, float spValue) {
   final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;  
   return (int) (spValue * fontScale + 0.5f);  
 }
}

自定义组合控件,然后实现相关的手势,思路很清晰,代码也很详细,这里就直接贴代码了。
activity_main.xml


<?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">

<LinearLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_centerInParent="true"
   android:orientation="vertical">

<com.jackie.slidebarviewdemo.widget.SlideBarView
     android:id="@+id/slide_bar"
     android:layout_width="match_parent"
     android:layout_height="50dp"
     android:layout_marginLeft="20dp"
     android:layout_marginRight="20dp"/>

<TextView
     android:id="@+id/text_view"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_gravity="center_horizontal"
     android:layout_marginTop="20dp"
     android:textColor="#000"
     android:textSize="20dp"
     android:text="当前是第0页"/>
 </LinearLayout>
</RelativeLayout>

activity_main.xml


<?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">

<RelativeLayout
   android:id="@+id/slide_bar_view"
   android:layout_width="match_parent"
   android:layout_height="50dp">

<View
     android:layout_width="match_parent"
     android:layout_height="5dp"
     android:layout_centerInParent="true"
     android:background="@drawable/shape_slide_bar_bg"/>

<View
     android:id="@+id/slide_bar_block"
     android:layout_width="20dp"
     android:layout_height="14dp"
     android:background="#b9b9b9"
     android:layout_centerVertical="true" />
 </RelativeLayout>
</RelativeLayout>

popup_window.xml


<?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">
 <RelativeLayout
   android:layout_width="30dp"
   android:layout_height="30dp">
   <TextView
     android:id="@+id/popup_text"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:textColor="#fff"
     android:textSize="16dp"
     android:gravity="center"
     android:layout_centerInParent="true" />
 </RelativeLayout>
</RelativeLayout>

附上相关的资源文件:
shape_slide_bar_bg.xml


<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
 android:shape="rectangle">
 <solid android:color="#dcdcdc" />
 <corners android:radius="1dp"/>
</shape>

popup_window_bg.9.png

Android仿IOS ViewPager滑动进度条

效果如下:

Android仿IOS ViewPager滑动进度条

标签:Android,ViewPager,进度条
0
投稿

猜你喜欢

  • Android App中ViewPager与Fragment结合的一些问题解决

    2023-08-02 22:22:43
  • springboot 定时任务@Scheduled实现解析

    2023-11-10 16:18:24
  • 关于重写equals()方法和hashCode()方法及其简单的应用

    2023-08-01 06:48:13
  • SpringMVC结构简介及常用注解汇总

    2023-10-25 09:16:59
  • Spring @CrossOrigin 注解原理实现

    2022-09-03 10:40:04
  • java对象类型转换和多态性(实例讲解)

    2023-06-23 16:33:53
  • C#使用Data Annotations进行手动数据验证

    2022-11-19 11:23:15
  • Java多维数组和Arrays类方法总结详解

    2022-04-27 22:30:18
  • 基于java构造方法Vector创建对象源码分析

    2023-11-25 11:27:54
  • 详解Swagger接口文档和常用注解的使用

    2023-11-24 15:35:21
  • Android自动播放Banner图片轮播效果

    2022-09-06 05:55:42
  • Java 添加和删除PDF图层的示例代码

    2022-09-03 00:29:01
  • android跑马灯出现重复跳动以及不滚动问题的解决方法

    2023-07-24 00:33:48
  • 将JavaDoc注释生成API文档的操作

    2023-06-16 18:24:06
  • springmvc图片上传及json数据转换过程详解

    2022-02-25 17:11:14
  • Spring Feign超时设置深入了解

    2022-01-17 10:39:06
  • Android屏幕适配工具类 Android自动生成不同分辨率的值

    2022-03-07 13:45:39
  • Spring Boot conditional注解用法详解

    2022-03-19 02:32:25
  • SpringBoot+Jpa项目配置双数据源的实现

    2022-11-01 14:05:04
  • C#使用for循环移除HTML标记

    2022-02-02 08:35:23
  • asp之家 软件编程 m.aspxhome.com