Android仿IOS ViewPager滑动进度条

最近做项目,碰到如下的需求: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

效果如下:

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

(0)

相关推荐

  • Android仿淘宝详情页面viewPager滑动到最后一张图片跳转的功能

    需要做一个仿淘宝客户端ViewPager滑动到最后一页,再拖动的时候跳到详情的功能,刚开始没什么思路,后来搜了一下,发现有好几种实现方法,最好的一种就是在ViewPager图片的后面再加一个view,然后滑动viewpager的时候,判断一下就行了. 附一个链接,我写的代码就是参考的这个,稍微改了一点点,先看看效果图. 实现起来比较简单,先写一个滑动加载详情的布局,然后在viewpager的instantiateItem里面判断一下,如果是最后一张,就显示加载详情的那个布局.不过需要注意的是,v

  • Android 中SwipeRefreshLayout与ViewPager滑动事件冲突解决方法

    Android 中SwipeRefreshLayout与ViewPager滑动事件冲突解决方法 问题描述: 开发中发现,SwipeRefreshLayout的下拉刷新,与ViewPager开发的banner的左右滑动事件有一点冲突,导致banner的左右滑动不够顺畅.很容易在banner的左右滑动的过程中,触发SwipeRefreshLayout的下拉刷新,从而导致banner左右滑动的体验很差. 解决方案: 可以在ViewPager的滑动时候设置SwipeRefreshLayout暂时不可用,

  • Android之禁止ViewPager滑动实现实例

    Android之禁止ViewPager滑动实现实例 当我们想在同一个Activity或者Fragment中展示多个页面时往往会用到ViewPager,通过滑动,我们可以很方便地在不同的页面中切换.但是在某些情况下我们可能并不需要通过滑动来切换ViewPager中的页面(比如为了避免跟页面内的某些触摸事件冲突),而是希望只点击下面或者上面的按钮来切换页面.像知乎那样: 那么有什么方法可以实现不滑动ViewPager呢?其实很简单,只需要自定义一个不滑动的ViewPager就可以了.ViewPage

  • Android仿IOS ViewPager滑动进度条

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

  • iOS中WKWebView仿微信加载进度条

    本文实例为大家分享了WKWebView仿微信加载进度条的具体代码,供大家参考,具体内容如下 WKWebView添加了estimatedProgress属性(double类型),我们可以利用该属性来设置UIProgressView github代码仓库上存放的Demo 为页面添加UIProgressView属性 @property (nonatomic, strong) WKWebView *mywebView; @property (nonatomic, strong) UIProgressVi

  • Android仿IOS回弹效果 支持任何控件

    本文实例为大家分享了Android仿IOS回弹效果的具体代码,供大家参考,具体内容如下 效果图: 导入依赖: dependencies { // ... compile 'me.everything:overscroll-decor-android:1.0.4' } RecyclerView 支持线性布局和网格布局管理器(即所有原生Android布局).可以轻松适应支持自定义布局管理器. RecyclerView recyclerView = (RecyclerView) findViewByI

  • android实现音乐播放器进度条效果

    本文实例为大家分享了android实现音乐播放器进度条效果的具体代码,供大家参考,具体内容如下 效果图 依赖3个对象 MediaPlayer:实现音乐播放,暂停,缓冲. SeekBar:滑动的进度条. java.util.Timer:定时器,时时更新进度条. main.xml样式文件 <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android

  • Android仿IOS上拉下拉弹性效果的实例代码

    用过iphone的朋友相信都体验过页面上拉下拉有一个弹性的效果,使用起来用户体验很好:Android并没有给我们封装这样一个效果,我们来看下在Android里如何实现这个效果.先看效果,感觉有些时候还是蛮实用的. 思路:其实原理很简单,实现一个自定义的Scrollview方法(来自网上大神),然后在布局文件中使用自定义方法Scrollview就可以了. 代码: 自定义View,继承自Scrollview.MyReboundScrollView类 package com.wj.myrebounds

  • Android仿微信左右滑动点击切换页面和图标

    本文实例为大家分享了Android仿微信左右滑动点击切换页面和图标的具体代码,供大家参考,具体内容如下 目标效果: 使用鼠标滑动屏幕或者点击下边的小图标,可以更改页面和图标,因为没有那么多素材所以只用了两张图片区分. 1.layout文件夹下新建top.xml页面,作为顶部标题. top.xml页面: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="h

  • Android编程实现WebView添加进度条的方法

    本文实例讲述了Android编程实现WebView添加进度条的方法.分享给大家供大家参考,具体如下: 标准的XML界面 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"

  • Android view自定义实现动态进度条

    Android  自定义view实现动态进度条 效果图: 这个是看了梁肖的demo,根据他的思路自己写了一个,但是我写的这个貌似计算还是有些问题,从上面的图就可以看出来,左侧.顶部.右侧的线会有被截掉的部分,有懂得希望能给说一下,改进一下,这个过程还是有点曲折的,不过还是觉得收获挺多的.比如通动画来进行动态的展示(之前做的都是通过Handler进行更新的所以现在换一种思路觉得特别好),还有圆弧的起止角度,矩形区域的计算等!关于绘制我们可以循序渐进,比如最开始先画圆,然后再画周围的线,最后设置动画

  • Android编程开发实现带进度条和百分比的多线程下载

    本文实例讲述了Android编程开发实现带进度条和百分比的多线程下载.分享给大家供大家参考,具体如下: 继上一篇<java多线程下载实例详解>之后,可以将它移植到我们的安卓中来,下面是具体实现源码: DownActivity.java: package com.example.downloads; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.net.H

  • Android自定义带水滴的进度条样式(带渐变色效果)

    一.直接看效果 二.直接上代码 1.自定义控件部分 package com.susan.project.myapplication; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.grap

随机推荐