仿华为ViewPager指示器开发教程

***本文纯手打,转载注明出处***

 

先看一下效果图:华为荣耀6的主题界面:

 

开发教程-viewpager指示器"> 

 

注意标题下的小圆点,本博客就是为了完成它.

 

思路:

 

布局方面:

 

上方一个LinearLayout,下面是一个ViewPager

 

功能方面:

 

LinearLayout肯定需要自定义,初始时,在第一个”推荐”的下面画上一个小圆点,然后通过viewpager的addOnPageChangeListener里的onPageScrolled方法,完成小圆点位置随页面滑动而变化。其实也挺简单的哈!接下来先上代码,然后讲一下原理。

 

首先自定义一个LinearLayout

MyLinearLayout:

package cn.zmit.myapplication;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.text.BoringLayout;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;

/**
 * Created by kyle on 2016/3/14.
 */
public class MyLinearLayout extends LinearLayout {
    private int startX;//初始位置X坐标
    private Paint mPaint;
    private int moveX;//移动时不断变化的X坐标

    public MyLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
        mPaint.setColor(Color.parseColor("#FFFFFF"));//画笔颜色
        mPaint.setStyle(Paint.Style.FILL);//画笔样式(填充内部)
    }

    public MyLinearLayout(Context context) {
        super(context, null);
    }

    /***
     * 开始画圆
     *
     * @param canvas
     */
    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        startX = getWidth() / 8;//最开始位置的X坐标
        canvas.save();//保存
        canvas.drawCircle(startX + moveX, getHeight() - 15, 5, mPaint);
        canvas.restore();//取出
    }

    /***
     * 当手指滑动时调用这个方法(在viewpager的onPageScrolled方法调用)
     *
     * @param position
     * @param Offset
     */
    public void changed(int position, float Offset) {
            moveX = (int) (getWidth() / 4 * Offset + position * getWidth() / 4);
            invalidate();//刷新
    }
}
既然用到ViewPager,当然需要fragment;

MyFragment.java:

package cn.zmit.myapplication;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * Created by Administrator on 2016/3/14.
 */
public class MyFragment extends Fragment {
    public static final String TITLE = "title";

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        TextView textView = new TextView(getActivity());
        textView.setText(getArguments().getString(TITLE));
        textView.setTextColor(Color.parseColor("#000000"));
        textView.setGravity(Gravity.CENTER);
        return textView;
    }

    public static MyFragment getInstance(String title) {
        Bundle pBundle = new Bundle();
        pBundle.putString(TITLE, title);
        MyFragment fragment = new MyFragment();
        fragment.setArguments(pBundle);
        return fragment;
    }
}
MainActivity.java:

 

package cn.zmit.myapplication;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.Window;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MainActivity extends FragmentActivity {
    private MyLinearLayout mLinearLayout;
    private ViewPager mViewpager;
    private FragmentStatePagerAdapter adapter;
    public List<String> lists = Arrays.asList("推荐", "排行", "分类","我的");
    private List<MyFragment> list = new ArrayList<>();

    private void assignViews() {
        mLinearLayout = (MyLinearLayout) findViewById(R.id.linearLayout);
        mViewpager = (ViewPager) findViewById(R.id.viewpager);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        assignViews();
        initData();
    }

    private void initData() {
        for (String title : lists) {
            MyFragment fragment = MyFragment.getInstance(title);
            list.add(fragment);
        }
        adapter = new FragmentStatePagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return list.get(position);
            }

            @Override
            public int getCount() {
                return list.size();
            }
        };
        mViewpager.setAdapter(adapter);
        mViewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                mLinearLayout.changed(position, positionOffset);
            }

            @Override
            public void onPageSelected(int position) {

            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }

}
好了,接下来开始讲一下原理。

这个例子最重要的地方,大家都能知道,在于自定义的LinearLayout,我们先从这里说起吧。

首先,

private int startX;//初始位置X坐标
private Paint mPaint;
private int moveX;//移动时不断变化的X坐标
startX为初始化原点的x坐标

maveX为当我们滑动ViewPager时动态改变的X数值。

然后,在构造方法中,初始画笔mPaint,设置颜色等属性。

接着,在dispatchDraw方法中执行画图功能,这个方法系统自动调用,主要是分发给子组件进行绘制。

代码解析:

startX = getWidth() / 8;//最开始位置的X坐标
初始化startX为屏幕的1/8,因为布局被分为4块,而原点又要位于每个模块的中间,所以初始的X应该为屏幕宽度的1/8。

canvas.save();//保存
canvas.drawCircle(startX + moveX, getHeight() - 15, 5, mPaint);
canvas.restore();//取出
sava和restore方法用于保存画布画图之前的状态和取出之前的状态,绘图时最好带上,这里不说了,有兴趣的同学可以去了解下。

drawCircle方法,顾名思义,画圆,第一个参数代表当前X坐标;第二个参数是高度,全程固定为布局的高度减去15,

大概在字和底部的中间。这个数值可以自己改,改到自己喜欢为止;第三个参数是半径,这里设为5,同理,可以根据喜好改;第四个参数是画笔,之前初始化完成了,这里直接加进去。

先看一下效果:

1

最后,重头戏来了,大家还记得在之前的ViewPager的addOnPageChangeListener里的onPageScrolled中做了什么吗?没错,在里面调用了一个方法:changed,让我们看一下,这个方法里做了什么

public void changed(int position, float Offset) {
        moveX = (int) (getWidth() / 4 * Offset + position * getWidth() / 4);
        invalidate();//刷新
}
看里面内容,将moveX的值变成了getWidth() / 4 * Offset + position * getWidth() / 4。

这到底是多少呢?先介绍一下两个参数,Offset,即滑动的宽度的百分比,比如我手指向左滑动,那么ViewPager的当前fragment也会随着手指往左边移动,当前fragment被隐藏的宽度占当前fragment的总宽度的百分比,即为Offset。Position就是当前fragment为第几个fragment,第一个的话,postion就为0,因为从0开始嘛!(注意,手指往左滑,position为当前position,手指往右滑,position为当前position-1)

介绍完参数后,开始说一下这个moveX到底变成了多少。

getWidth/4,屏幕宽度的1/4,即一个模块的宽度,乘以Offset,即随着手指滑动,使moveX的数值一直变大,直至正好为一个模块的宽,也就是从一个模块,滑到了另一个模块。听着已经可以了,但是不要忘记,Offset每次滑动后,都会变成0,也就是说,假设就这样完事的话,你只能将小圆点从第一个模块移动到第二个模块,无论你怎么滑。

好了,接着,后面还加了position * getWidth() / 4,即当前fragment的position乘以当前模块的宽,这样就解决了只能滑到第二个模块的问题,因为假设当前fragment为第二个,position为1,原点位于模块2,即“排行”,X的数值为X=startX+moveX;

startX=getWidth() / 8 ;

moveX=getWidth() / 4 * Offset + 1* getWidth() / 4;

当我们没动时,X的数值等于”排行”两字中间的X值,

X=getWidth() / 8+1* getWidth() / 4;

当我们往左滑动,Offset不断变大,直至1,position为1

X=getWidth() / 8+getWidth() / 4 +1* getWidth() / 4;

正好比没滑动时大一个模块,即滑到了第三个模块”分类”

当我们往右滑动,Offset不断变大,直至1,position为0

X=getWidth() / 8+getWidth() / 4 +0* getWidth() / 4;

正好比没滑动时小一个模块,即滑到了第一个模块”推荐”

效果图由于条件限制,没法录制gif,所以大家可以自己把代码运行一下看效果。

总结:这个例子主要是运用了viewGroup的画图功能,自定义了一个带圆点的LinearLayout,随后运用ViewPager的滑动参数,动态改变圆点位置。主要在于了解viewPager的运行机制,还有需要了解画笔的使用。

原文来自 :http://blog.it985.com/15824.html

时间: 2025-01-21 17:19:01

仿华为ViewPager指示器开发教程的相关文章

安卓UI设计与开发教程 顶部标题栏(五)两种方式实现仿微信标题栏弹窗效果

博主在这篇文章中将会继续围绕顶部标题栏专题来进行实例讲解,今天要讲解的主题是分别使用 PopupWindow和Activity两种不同的方式来实现仿微信顶部标题栏弹窗的这样一个效果. 一.实现效果 图 这里为了演示方便,我将两种方法放在一个应用程序中演示,这个是主界面 开发教程 顶部标题栏(五)两种方式实现仿微信标题栏弹窗效果-js修改微信顶部标题栏"> 虽 然两种实现的方式不一样,但是最终的效果图都是差不多的

Android UI设计与开发教程 引导界面(四)仿人人网V5.9.2最新版引导界面

这一篇我将会以人人网的引导界面为实例来展开详细的讲解,人人网的引导界面比较的新颖,不同于其他 应用程序千篇一律的靠滑动来引导用户,而是以一个一个比较生动形象的动画效果展示在用户们的面前,有一 种给人眼前一亮的感觉,话不多说,进入正题. 一.实现的效果图 欢迎界面: 开发教程 引导界面(四)仿人人网V5.9.2最新版引导界面-变色龙引导最新版"> 引 导界面1

Android应用中仿今日头条App制作ViewPager指示器_Android

一.概述顶部ViewPager指示器的字体变色,该效果图是这样的: 大概是今天头条的app,神奇的地方就在于,切换ViewPager页面的时候,顶部指示器改成了字体颜色的变化,个人觉得还是不错的. 那么核心的地方就是做一个支持字体这样逐渐染色就可以了,我大概想了32s,扫描了一些可能实现的方案,最终定位了一个靠谱的,下面我就带大家开始实现的征程. 实现之前贴一下我们的效果图:1.简单使用 效果如上图了,关于颜失色的改变我添加了两个方向,一个是左方向,一个是有方向. 单纯的使用,可能觉得没什么意思

Android应用中使用ViewPager和ViewPager指示器来制作Tab标签_Android

一.ViewPageIndicator开源框架的基本用法 我们先得去Github上面下载这个库,下载地址:https://github.com/JakeWharton/Android-ViewPagerIndicator,下载下来之后你可以运行例子,来看看我们需要什么样的效果,然后在此基础上改成我们自己想要的效果 1.如何使用开源框架第1步:improt library项目 第2步:导入library进我们自己新建的项目 从Github上Download下来这个zip包之后,里面会有一个libr

安卓UI设计与开发教程 底部菜单栏(四)

Fragment+PopupWindow仿QQ空间最新版底部菜单栏 在今天的这篇文章当中,我依然会以实战加理论结合的方式教大家如何设计出自己觉得很炫的UI界面.好的,话不多说,进入正题.今天的这篇文章主要是以仿QQ空间的底部菜单栏效果为主,实现的效果有: <1>实现了点击按钮时的切换图片效果: <2>实现了点击按钮时的切换界面效果: <3>实现了点击中间圆形按钮时弹出菜单以及按钮图片切换效果: <4>实现了点击空白处和返回键按钮来关闭弹出菜单. 有个地方需要

Android简明开发教程二十二:使用资源Resources

在前面的例子中,我们忽略了一个重要的原则,在代码和Layout中,直接使用了字符串常量,比如: <Button android:text="Pattern" android:id="@+id/btnPattern" android:layout_width="wrap_content" android:textColor="@color/black" android:checked="true" an

Flash CS3 组件开发教程

教程|组件开发 [教程说明]:应云开等朋友的要求,我今天把组件开发过程整理一下,写成这篇教程.通过此篇教程你可以大致了解Flash 组件开发整个过程,希望对那些想自己开发Flash 组件的朋友有所帮助.我这次主要开发Flash 代码组件,甚至其他Flash 组件,你可以自行研究或和我一起讨论. [前提条件]:1.安装了Flash CS3软件:2.安装了Adobe Extension Manager 1.8 扩展管理器,如果没有请先到这里下载: [开发教程]:1.首先准备一个18x18的png 图

Windows Phone 7开发教程(4)——XNA显示中文字体

我最近勤快地连自己都有些不可思议.昨天有朋友在上一篇文章里留言,批 评Windows Phone 7暂时没有支持中文版的问题.凡事都有个过程,在中文版出 来前,咱们想自己想点办法吧.Silverlight for Windows Phone那边就不管了 ,肯定会有人想出办法来的.如何让Windows Phone 7游戏显示中文?把说"贴 图"的那个人拖出去打死!因为XNA 4.0中支持中文的办法倒是现成的,这与XNA 字体支持的方式有很大关系. 示例代码下载地址: http://fil

微信公众帐号开发教程(13) 图文消息全攻略

引言及内容概要 已经有几位读者抱怨"柳峰只用到文本消息作为示例,从来不提图文消息,都不知 道图文消息该如何使用",好吧,我错了,原本以为把基础API封装完.框架搭建好,再给出一个文本消息的 使用示例,大家就能够照猫画虎的,或许是因为我的绘画功底太差,画出的那只猫本来就不像猫吧-- 本篇主要介绍微信公众帐号开发中图文消息的使用,以及图文消息的几种表现形式.标题取名为"图 文消息全攻略",这绝对不是标题党,是想借此机会把大家对图文消息相关的问题.疑虑.障碍全部清除掉.