1. 程式人生 > >Android仿IOS ViewPager滑動進度條

Android仿IOS ViewPager滑動進度條

最近做專案,碰到如下的需求:ViewPager分頁,如果是6頁(包括6頁)就用圓點,如果是6頁以上就用進度條來切換。前面一種互動方法最常見,用小圓點來表示當前選中的頁面,這些小圓點稱為導航點,很多App都是這種實現方式。當用戶第一次安裝或升級應用時,都會利用導航頁面告訴使用者當前版本的主要亮點,一般情況下當行頁面有三部分組成,背景圖片,導航文字和滑動的原點,即下面的效果:


這裡就不作詳細的講解,大家可以參考我以前寫過的部落格:

今天來實現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滑動進度

最近做專案,碰到如下的需求:ViewPager分頁,如果是6頁(包括6頁)就用圓點,如果是6頁以上就用進度條來切換。前面一種互動方法最常見,用小圓點來表示當前選中的頁面,這些小圓點稱為導航點,很多App都是這種實現方式。當用戶第一次安裝或升級應用時,都會利用導航頁面告訴使用者

android仿照IOS AppStore下載進度

下面有效果圖,本人也是在網上搜集進度條之後修改而成,不喜勿噴! 先上效果圖 public class TasksCompletedView2 extends View {// 畫最外邊圓環的畫筆private Paint mCirclePaint;// 畫圓環的畫筆pr

Android仿iOS左右滑動開關控制元件(Android4.0以上適用)

上週使用Android的switch模仿iOS的左右滑動開關控制元件,程式碼如下: aty_switch.xml: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android

Android (仿支付寶) 收益進度

一、 看效果 二、上程式碼 package com.framework.widget; import android.app.Activity; import android.content.Context; import android.content.res

Android仿IOS滑動按鈕

專案結構 MainActivity public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedIns

Android-SeekBar可滑動進度

目標效果:     程式執行顯示進度條在中間,手指滑動可更改進度條位置,並且顯示在TextView上,當點選進度條按鈕或者拖動時,按鈕變為紅色,擡起手指變為黑色。 1.activity_main.xml頁面設定控制元件。 activity_main.xml頁面: <

仿163首頁的廣告收縮效果/選單滑動/進度

首頁的廣告收縮效果 <style> #top{     position:relative; } #content{     position:absolute; }      </style> </head> <body onlo

仿ios滑動效果

public 頭部 ati 設置 class iss generated ttr stat package code.suibianchou.com.custormview2;import android.annotation.SuppressLint;import and

Framework7新版學習筆記之 滑動進度

滑動 left data- val 滑塊 改變 進度條 筆記 spa 一:滑動進度條 滑動進度條是指:可以拖動來改變進度值的控件,例如:音量設置、亮度設置等。 二:定義滑動進度條 1:單邊滑塊進度條 滑塊從0~max進行滑動,滑塊所處位置就是

Android仿ios微信左劃條目刪除、置頂的實現,程式碼簡潔,更容易理解使用

<span style="font-family:Arial, Helvetica, sans-serif;"><span style="background-color: rgb(255, 255, 255);">歡迎大家</span></span

Android控制元件之圓形進度

Android-自定義ProgressBar實現圓弧進度條 在之前的專案中用到過這個,感覺還是非常實用的,我實現的是額度的增長. 繼承於ProgressBar實現,保留了Progressbar的特性,原始碼在文尾。

Android仿ios底部彈框,支援傳入list集合,任意配置個數

不說廢話,一看程式碼誰都懂。   public class BottomDialog { private Context context; private Dialog dialog; private TextView txt_title; p

iOS實現音訊進度效果

這篇文章主要介紹了iOS實現音訊進度條效果,本文寫了一個小demo通過例項程式碼相結合的形式給大家詳細介紹,需要的朋友可以參考下 話不多說先上效果圖 看到這個效果的時候我感覺相對比較難的點有兩點: 一、是這個進度條的進度顏色變化,這裡思路還是比較清晰的,直接用layer的mas

android——(圖片框與進度

1. Toast(吐絲框)   1.1 Toast是Android中的一種簡易的訊息提示框   1.2 使用這個類的最簡單的方法是呼叫靜態方法構造您所需要的一切,並返回一個新的Toast物件。       Toast toast=Toast.m

Android】一、Progress進度實現的三種方式:主執行緒實現,Service載入,動態建立

前言 更新版本,上傳資料到服務端,都是需要進度顯示的,Android進度顯示兩種方式 ProgressDialog 和 ProgressBar 新版本中ProgressDialog不被推薦使用,所以專案採用ProgressBar 分為三種實現方式: 1、MainAct

Android 常用效果(各種進度,酷炫loading動畫,火箭升空,撒花以及趨勢圖)

最近時間比較充裕一些,總結了下幾個專案用到的ui效果,在這邊共享給大家,也給自己做個記錄(後面會有demo貼出). 主要是以下幾種ui效果: 進度條多種展示 開源loading動畫 火箭升空 撒花

Android仿Ios實現Dialog圓角彈窗

轉載請標明出處:https://blog.csdn.net/m0_38074457/article/details/84979890 ,本文出自:【陳少華的部落格】 一、先看效果 https://github.com/hnsycsxhzcsh/IosDialog/blob/m

android仿ios時間控制元件

如果您認為本部落格不錯,讀後覺得有收穫,不妨打賞讚助我一下,讓我有動力繼續寫出高質量的部落格。 贈人玫瑰,手有餘香。分享技術,傳遞快樂。 有心課堂,傳遞的不僅僅是技術! QQ交流群:250468947 有心課堂會員,請加入VIP QQ交流

Android自定義View-圓形進度

好幾天不寫部落格了,這段時間一直沒時間,感覺一直在忙,但是進度不大。 好了,言歸正傳,最近專案裡要用到這麼一個自定義view,是一個圓形的進度圓環,現在學習下怎麼來自定義它。 原始碼下載地址 自定義之前先分析一下,這個自定義View主要有以下幾

Android 仿iOS帶有星期幾的日期時間選擇器

最近看到一個需求,就是日期時間選擇器上面需要帶有星期幾來供使用者滑動選擇,我上網搜了一些發現很多demo都跟我以前寫過的一篇日期時間選擇器差不多,(點選檢視我以前寫過的日期時間選擇器)找不到帶有星期幾的日期時間選擇器,於是自己就研究了一下。實現效果如下 發