Android仿IOS ViewPager滑动进度条

#技术教程 发布时间: 2026-01-18

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

这里就不作详细的讲解,大家可以参考我以前写过的博客:
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


效果如下:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。




上一篇 : mysql中COUNT函数用法_mysql COUNT函数使用方法

下一篇 : SQL数据库建模怎么做_深入讲解快速提升实战能力【教程】

推荐阅读

电话:400 76543 55
邮箱:915688610@qq.com
品牌营销
客服微信
搜索营销
公众号
©  丽景创新 版权所有 赣ICP备2024032158号 
宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 恩施州毯滚百货有限公司 恩施州毯滚百货有限公司 襄阳市蜂欢商贸有限公司 襄阳市蜂欢商贸有限公司 恩施州换冯百货有限公司 恩施州换冯百货有限公司 恩施州健提百货有限公司 恩施州健提百货有限公司 西安益零商贸有限公司 西安益零商贸有限公司 南奥教育 南奥教育 南奥教育 南奥教育 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南奥教育网 南奥教育网 南奥教育网 南奥教育网 南奥学习网 南奥学习网 南奥学习网 南奥学习网 南奥教育 南奥教育 南奥留学记 南奥留学记 南奥教育 南奥教育 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 广照天下广告 广照天下广告 广照天下广告策划 广照天下广告策划 广照天下 广照天下 广照天下 广照天下 广照天下 广照天下 广照天下广告策划 广照天下广告策划 广照天下广告策划 广照天下广告策划 南昌市广照天下广告策划有限公司 南昌市广照天下广告策划有限公司 南昌市广照天下广告策划有限公司 南昌市广照天下广告策划有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司
品牌营销
专业SEO优化
添加左侧专家微信
获取产品详细报价方案