Android之实现ViewPagerIndicator
PS:最近一直忙于学习任务,一直没有时间去写博客.今天周六,终于有时间了.
学习任务:
1.打造一个自己的ViewPagerIndicator
最近被安排了一大堆的学习任务,感觉老板还是很好的,让我们在业余时间多提升自己的个人能力,就拿这个ViewPagerIndicator来说吧,当初自己没有什么好的实现方案,现在也就学了一发,看了一下Google上的实现方案,针对的情况比较的多,我这里就针对一种情况来说.大家想更深入的研究可以去Github上搜索一下Google工程师的实现方式,效果都很棒,有兴趣的可以全部研究一下.我看了一下鸿洋的实现方式,不过他做的是三角形的.我做的是线条状的,因此做了一些修改.
原理还是比较简单的,下面是一个ViewPager,上面整体是一个ViewPagerIndicator.然后在最下面画一个线条当做指示符就可以了,当ViewPager在滑动的时候,我们只需要知道偏移的距离,然后重新绘制这条指示符,调用invalidate()函数重新绘制视图就可以了。
首先说一下如何画才是关键,画出这个指示符其实就是画出一个实心的矩形,我们需要知道矩形的长度和宽度,以及在什么位置进行绘制,一般高度我们自己是可以人为指定的,我们需要多高就可以指定成多少单位个dp,最后转换成px就可以了,但是宽度呢?宽度其实 = 屏幕宽度 / 显示的ViewPager的数量,获取屏幕的宽度还是比较简单的,因为我们已经在xml文件中指定了这个ViewPagerIndicator的宽度,我们只需要测量一下就能够拿到他的具体宽度.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mTop = getMeasuredHeight();
int width = getMeasuredWidth();
int height = mTop + DensityUtils.dip2px(context, mHeight);
mWidth = width / mTabVisibleCount;
setMeasuredDimension(width, height);
}
这样我们就能够获取到整个ViewPagerIndicator的高度和宽度,那么矩形指示符的 mTop(顶部起始位置) = getMeasureHeight(); 因为指示符也是需要高度的,因此我们需要重新设置整个ViewPagerIndicator的高度,因此这里需要调用setMeasuredDimension(width,height)重新设置整个ViewPagerIndicator的高度和宽度。有了这个思路,我们就能够绘制出这个矩形的指示符。那么还有一个难题,就是如何设置显示的数量.总不能在自定义的时候写死吧.这样不是非常的灵活,并且在实际项目开发的时候,不同的页面,需要的指示符的数量也是不相同的.因此这里我们需要使用一种灵活的方式去设置指示符的显示数量.
灵活的设置指示符的显示数量需要自定义视图属性,需要在attrs文件中进行声明.
<?xml version="1.0" encoding="utf-8"?>
<resources> <!--属性的名字以及对应的类型-->
<attr name="item_count" format="integer"></attr> <!--声明自定义属性,与上面形成关联关系-->
<declare-styleable name="ViewPagerIndicator">
<attr name="item_count" />
</declare-styleable> </resources>
那么这东西如何使用呢?首先我们需要在xml文件中进行设置.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<!--这里需要引入命名空间-->
xmlns:rzx="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <!--修改显示数量
rzx:item_count="我们想设置的数值",这里我设置了5个
前面这个名字是命名空间,可以随便设置.
-->
<com.example.totem.myviewpagerindicator.view.ViewPagerIndicator
android:layout_width="wrap_content"
android:layout_height="wrap_content"
rzx:item_count="4"> </com.example.totem.myviewpagerindicator.view.ViewPagerIndicator> </LinearLayout>
因为我们是自定义控件实现的,因此我们需要在我们自定义的ViewPagerIndicator中去获取我们声明的显示数量.然后去指定指示符的显示宽度.这样就可以根据自己定义的显示数量去指定指示符的宽度了.
public ViewPagerIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
/**
* 存放自定义视图属性的数组容器,需要在attrs文件夹中定义属性
* 属性支持:
* reference string color dimension boolean integer float fraction enum flag
* */
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator);
/**
* 获取数组容器中属性数量
* */
mTabVisibleCount = typedArray.getInt(R.styleable.ViewPagerIndicator_item_count, COUNT_DEFAULT_TAB);
if (mTabVisibleCount <= 0) {
mTabVisibleCount = COUNT_DEFAULT_TAB;
}
/**
* 调用recycle()函数
* */
typedArray.recycle();
}
获取过程就需要使用TypedArray去进行获取,它是存放自定义视图的一个数组容器,支持的类型在上面已经声明了,我就不进行啰嗦了.obtainStyledAttributes()这个方法顾名思义,获取Styled中声明的属性,那么从哪里获取呢?从我们的attrs文件夹中获取,那么获取那个值呢?获取的就是我们声明的ViewPagerIndicator名字的属性值.因为我们已经指定了显示的数量,因此他就可以获取到我们指定的数值,如果获取不到,那么就会有一个默认值.就这么简单,这里recycle()函数是为了再次利用typedArray。不调用也没有什么问题.
那么拿到了显示数量,以及整体宽度,我们就可以去绘制这个矩形指示符了.
public Rect(int left, int top, int right, int bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
绘制矩形需要传递四个参数,top我们已经获取到了.起初的ViewPagerIndicator的高度位置.bottom就是最终的ViewPagerIndicator的高度,left的获取其实是比较重要的,其实他的位置也很容易获取.left = (position(当前位置) + offset(偏移量)) * mWidth(指示符的宽度). left1(第一个位置的指示符位置) = (0 + 0) * mWidth。偏移的过程中,offset是始终改变的.那么这个left也是随之变动的.然后不断的重新绘制.
/**
* 指示符滚动
*/
public void scroll(int position, float offset) {
mLeft = (int) ((position + offset) * mWidth);
/**
* 重新绘制视图
* */
invalidate();
}
那么谁给我们时刻传递这个偏移量是个关键.偏移是一个过程,因此如果希望指示符是移动过去的,需要时刻获取当前的偏移量,这个偏移量就得交给ViewPager了.我们需要把我们的ViewPagerIndicator与ViewPager进行绑定,这样就能能够时刻获取到偏移量了.这取决于ViewPager的方法.
/**
* 设置关联的ViewPager
*/
public void setViewPager(ViewPager mViewPager, int pos) {
this.mViewPager = mViewPager;
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
scroll(position, positionOffset);
} @Override
public void onPageSelected(int position) {
resetTextViewColor();
highLightTextView(position);
} @Override
public void onPageScrollStateChanged(int state) { }
});
mViewPager.setCurrentItem(pos);
highLightTextView(pos);
}
ViewPager的滑动监听能够帮助我们时刻获取到偏移量.这里我们没有必要再对外暴露接口什么的了.如果还想做其他的操作,我们只需要封装方法.让其执行就可以了..剩下的就是一些琐碎的东西,比如说,改变字体的颜色,以及设置相关的点击事件等等.
/**
* 高亮文本
*/
protected void highLightTextView(int position) {
View view = getChildAt(position);
if (view instanceof TextView) {
((TextView) view).setTextColor(COLOR_SELECT);
}
} /**
* 重置文本颜色
*/
private void resetTextViewColor() {
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
if (view instanceof TextView) {
((TextView) view).setTextColor(COLOR_NORMAL);
}
}
} /**
* 设置点击事件
*/
public void setItemClickEvent() {
int cCount = getChildCount();
for (int i = 0; i < cCount; i++) {
final int j = i;
View view = getChildAt(i);
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mViewPager.setCurrentItem(j);
}
});
}
}
核心的地方基本都说完了.小细节问题就是在设置高度的时候别忘了dp和px之间的转换,否则画出来的线条实际上是有高度偏差的.MainActivity就只需要做一些初始化操作,为ViewPager添加相关的Fragment就行了.
package com.example.totem.myviewpagerindicator.activity; import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.Window; import com.example.totem.myviewpagerindicator.R;
import com.example.totem.myviewpagerindicator.fragment.FinallyFragment;
import com.example.totem.myviewpagerindicator.fragment.FirstFragment;
import com.example.totem.myviewpagerindicator.fragment.FouthFragment;
import com.example.totem.myviewpagerindicator.fragment.SecondFragment;
import com.example.totem.myviewpagerindicator.fragment.ThirdFragment;
import com.example.totem.myviewpagerindicator.view.ViewPagerIndicator; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; public class MainActivity extends FragmentActivity { private List<Fragment> mTabContents = new ArrayList<>();
private FragmentPagerAdapter mAdapter;
private ViewPager mViewPager;
private List<String> mDatas = Arrays.asList("1", "2", "3", "4", "5");
private ViewPagerIndicator mIndicator; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
initView();
initData();
//设置Tab上的标题
mIndicator.setTabItemTitles(mDatas);
mViewPager.setAdapter(mAdapter);
//设置关联的ViewPager
mIndicator.setViewPager(mViewPager, 0);
} private void initView() {
mViewPager = (ViewPager) findViewById(R.id.viewPager);
mIndicator = (ViewPagerIndicator) findViewById(R.id.Indicator);
} private void initData() { FirstFragment firstFragment = new FirstFragment();
SecondFragment secondFragment = new SecondFragment();
ThirdFragment thirdFragment = new ThirdFragment();
FouthFragment fouthFragment = new FouthFragment();
FinallyFragment finallyFragment = new FinallyFragment(); mTabContents.add(firstFragment);
mTabContents.add(secondFragment);
mTabContents.add(thirdFragment);
mTabContents.add(fouthFragment);
mTabContents.add(finallyFragment); mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) { @Override
public int getCount() {
return mTabContents.size();
} @Override
public Fragment getItem(int position) {
return mTabContents.get(position);
}
};
}
}
最后放上一个源代码分享:http://pan.baidu.com/s/1i56onAX
Android之实现ViewPagerIndicator的更多相关文章
- Android开源框架ViewPagerIndicator的基本使用
转载本博客请注明出处:点击打开链接 http://blog.csdn.net/qq_32059827/article/details/52495647 很多新闻资讯类的app都有一些共性,那就是 ...
- 老猪带你玩转android自定义控件一——打造最简单viewpagerindicator
viewpagerindicator,既使用viewpager翻页时候,标题的指示条随着改变的控件,是常用android控件之一,几乎所有的新闻类APP中都有使用.如下图所示: 今天,我们将从0到1实 ...
- Android stuido viewpagerindicator的使用
Top Level Build.gradle buildscript { repositories { maven { url "http://dl.bintray.com/populov/ ...
- android 项目学习随笔七(ViewPagerIndicator与ViewPager)
1.ViewPagerIndicator https://github.com/JakeWharton/ViewPagerIndicator package com.viewpagerindicato ...
- Android 使用Fragment,ViewPagerIndicator 制作csdn app主要框架
转载 转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/23513993 本来准备下载个CSDN的客户端放手机上,没事可以浏览浏览资 ...
- Android 教你打造炫酷的ViewPagerIndicator 不仅仅是高仿MIUI
1.概述 哈,今天给大家带来一个ViewPagerIndicator的制作,相信大家在做tabIndicator的时候,大多数人都用过 TabPageIndicator,并且很多知名APP都使用过这个 ...
- Android:ViewPager扩展的具体解释——导航ViewPagerIndicator(有图片缓存,异步加载图片)
我们已经用viewpager该. github那里viewpager扩展,导航风格更丰富.这个开源项目ViewPagerIndicator.非常好用,但样品是比较简单,实际用起来是非常不延长.例如,在 ...
- 第三方框架ViewPagerIndicator引入到Android Studio的方法总结
原创文章,转载请注明出处http://www.cnblogs.com/baipengzhan/p/6286619.html 第三方框架ViewPagerIndicator实现的效果比较好,但当我们从G ...
- 《Android进阶》之第四篇 ViewPagerIndicator的使用
1.先将这个开源框架下载到本地: Administrator@QH-20141231RFQJ /d/hixin $ cd ViewPagerIndicator/ Administrator@QH-20 ...
随机推荐
- Jquery 系列(1) 基本认识
本系列Jquery所用测试Demo版本是<uncompressed,development jQuery 1.11.3> 最新的jquery包可以从官网下载请参照http://jquery ...
- ENode框架Conference案例分析系列之 - 架构设计
Conference架构概述 先贴一下Conference案例的在线地址,UI因为完全拿了微软的实现,所以都是英文的,以后我有空再改为中文的. Conference后台会议管理:http://www. ...
- UI控件(UITextView)
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //UITextView与UITextField主要 ...
- 剑指Offer面试题:33.二叉树的深度
一.题目一:二叉树的深度 1.1 题目说明 题目一:输入一棵二叉树的根结点,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度.例如下图中的二叉树的 ...
- java中文乱码解决之道(三)-----编码详情:伟大的创想---Unicode编码
随着计算机的发展.普及,世界各国为了适应本国的语言和字符都会自己设计一套自己的编码风格,正是由于这种乱,导致存在很多种编码方式,以至于同一个二进制数字可能会被解释成不同的符号.为了解决这种不兼容的问题 ...
- 如何让用户只能访问特定的数据库(MSSQL)
背景 客户的SQL Server实例上有多个厂商的数据库,每个数据库由各自的进行厂进行商维护, 为了限定不同厂商的维护人员只能访问自己的数据库,现需要给各个厂商限定权限,让他们登录SQL Server ...
- S1293和S2220KTV项目结束
1.界面原型(前台的界面搭建一下) 2.数据库 3.架构设计 4.约定的文件抽取 2015年7月20日下午 歌星点歌三界面的联动,数据动态加载 01.点击第一个LIstView,弹出第二个ListVi ...
- [备忘]检索 COM 类工厂中 CLSID 为 {91493441-5A91-11CF-8700-00AA0060263B} 的组件时失败解决方法
检索 COM 类工厂中 CLSID 为 {91493441-5A91-11CF-8700-00AA0060263B} 的组件时失败,原因是出现以下错误: 80070005 在CSDN上总是有网友问这个 ...
- .NET 基础 一步步 一幕幕 [前言]
.NET 基础 一步步 一幕幕 [前言部分] 本人小白一枚,虽然说从去年就开通博客了,到现在也没有写多少东东,虽然工作了,也没有更好得总结.故此重新祭出博客园法宝,修炼技术,争取早日走上大神之位. 故 ...
- innerHTML,outerHTML,innerText,outerText区别以及insertAdjacentHTML()方法
在需要给文档插入大量的新的HTML标记的情况下,通过多次DOM操作先创建节点再指定它们之间的关系会非常麻烦而且效率不高,相对而言插入标记的方法会更加简单,速度也更快. 插入标记中有这四个属性inner ...