自定义控件是开发中经常使用的技术。系统中自带的ViewPager实现的功能有时候不能满足开发的需要,如ViewPager没有滑动图片时的动画切换效果。通过对 ViewPager的模仿和部分功能的加强,可以使学习者了解自定义ViewGroup的实现过程,以及系统动画的实现原理。

 

第一步:继承ViewGroup,就必须重载父类的构造方法,和onLayout()方法。首先创建一个类,起名MyViewPager,继承ViewGroup
public class MyViewPager extends ViewGroup {
private int page;//当前页的索引
private GestureDetector detector;//手势探测
private Context context;//控件创立的上下文
private MyScroller scroller;//缓慢页面切换帮助类,
private boolean isFling;//用于判断
private MyViewOnPageChangedListener listener;//页面变化监听事件
/**
*建立两个参数的构造函数,用于在布局文件中使用。在构造函数中,调用initView()方法初始化控件,创建GestureDetector对象,响应屏幕触摸事件。
*/
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
this.context=context;
// TODO Auto-generated constructor stub
initView();
}
public void initView(){
scroller=new MyScroller();
detector=new GestureDetector(context,new GestureDetector.OnGestureListener(){
 
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
 
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
 
}
 
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
/**
 * 图片缓慢滑动效果
 */
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// TODO Auto-generated method stub
scrollBy((int)distanceX,0);
return false;
}
 
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
 
}
/**
 * 图片快速滑动切换
 */
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
// TODO Auto-generated method stub
isFling=true;
if(velocityX<0&&page<getChildCount()-1){
page++;
}else if(velocityX>0&&page>0){
page--;
}
moveToDes(page);
return false;
}});
}
/** * 设置子view的布局,使其按照父控件的大小沿着水平方向展开 */
 
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
for(int i=0;i<getChildCount();i++){
getChildAt(i).layout(i*getWidth(),0,getWidth()+i*getWidth(),getHeight());
}
}
/**
* 重载onTouchEvent方法,设置page值,当手指滑动超过二分之一屏幕宽度时,切换到下一个或上一个页面,
* 当不足二分之一屏幕宽度时,页面不切换
*/
 
private int firstPosition;//记录手指按下时的位置
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
detector.onTouchEvent(event);
 super.onTouchEvent(event);
 
 switch (event.getAction()) {
 
case MotionEvent.ACTION_DOWN:
firstPosition=(int)event.getX();
break;
case MotionEvent.ACTION_UP:
/**
 * 用isFling区分缓慢移动和快速移动
 */
if(!isFling){
if(event.getX()-firstPosition>getWidth()/2){
page=page-1;
}else if(firstPosition-event.getX()>getWidth()/2){
page=page+1;
}
moveToDes(page);
break;
}
isFling=false;
}
 return true;
}
 
/**
 * 使其移动到page相应的页面
 * @param page
 */
public  void moveToDes(int page) {
// TODO Auto-generated method stub
if(page<=0){
page=0;
}
if(page>=getChildCount()-1){
page=getChildCount()-1;
}
/**
 * 迅速页面切换
 */
//scrollTo(page*getWidth(), 0);
/**
 * 添加页面变化监听,监听事件放入经常调用的方法里,显示事件的经常调用
 */
listener.onPageChanged(page);
 
//缓慢页面切换动画
int distance=page*getWidth()-getScrollX();
scroller.startScroll(getScrollX(), distance);
invalidate();//刷新页面,重画,并且重新执行computeScroll()
}
//重复执行该方法,实现动画效果
@Override
public void computeScroll() {
// TODO Auto-generated method stub
super.computeScroll();
if(scroller.isScrolling()){
scrollTo(scroller.getCurrentX(), 0);
invalidate();
}
 
}
 
/**
 * 设置监听事件方法
 * @param listener
 */
public void setPageChangedListener(MyViewOnPageChangedListener listener){
this.listener=listener;
}
/**
 * 监听事件接口,监听页面变化
 * @author Charles
 *
 */
interface MyViewOnPageChangedListener{
public void onPageChanged(int page);
}
 
}
 
第二步:自定义MyScroller
public class MyScroller {
public int distance;//动画运行距离
public int startX;//动画开始位置
public boolean isFinish;//判断动画是否完成
public int startTime;//动画开始时间
public int duration=500;//动画持续时间
public int currentX;//当前坐标
 
public void startScroll(int startX,int distance){
this.distance=distance;
this.startX=startX;
startTime=(int)SystemClock.uptimeMillis();
isFinish=false;
}
public boolean isScrolling(){
if(isFinish){
return false;
}
 
int lastTime=(int)SystemClock.uptimeMillis()-startTime;
if(lastTime<=duration){
currentX=startX+lastTime*distance/duration;//通过当前时间,判断当前位置
 
}else{
currentX=startX+distance;
isFinish=true;
}
return true;
}
public int getCurrentX(){
return currentX;
}
}
 
第三步:定义布局文件,将自定义的控件放到布局文件中
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.define_ViewPager.MainActivity" >
<RadioGroup
    android:id="@+id/group"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="30dp"/>
 
    <com.example.define_ViewPager.MyViewPager
        android:id="@+id/myViewPager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        />
 
</LinearLayout>
 
 
第四步:在Activity中,将准备好的图片加载到MyViewPager中
public class MainActivity extends Activity {
private MyViewPager viewPager;
private RadioGroup group;//选择按钮组
private int[] images={R.drawable.a1,R.drawable.a2,R.drawable.a3
,R.drawable.a4,R.drawable.a5,R.drawable.a6};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager=(MyViewPager) findViewById(R.id.myViewPager);
group=(RadioGroup) findViewById(R.id.group);
//加载图片
for(int i=0;i<images.length;i++){
View view=new View(this);
view.setBackgroundResource(images[i]);
viewPager.addView(view);
 
}
//添加单选按钮到group中
for(int i=0;i<viewPager.getChildCount();i++){
RadioButton button=new RadioButton(this);
button.setId(i);
if(i==0){
button.setChecked(true);
}
group.addView(button);
}
/**
 * 设置监听方法,当页面变化时,使相应的RadioButton选中
 */
viewPager.setPageChangedListener(new MyViewOnPageChangedListener(){
 
@Override
public void onPageChanged(int page) {
// TODO Auto-generated method stub
RadioButton button=(RadioButton)group.getChildAt(page);
button.setChecked(true);
 
}});
group.setOnCheckedChangeListener(new OnCheckedChangeListener(){
 
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
// TODO Auto-generated method stub
viewPager.moveToDes(checkedId);//移动到选中页
}});
}
 
}
 

模仿ViewPager控件的更多相关文章

  1. 安卓开发_深入学习ViewPager控件

    一.概述 ViewPager是android扩展包v4包(android.support.v4.view.ViewPager)中的类,这个类可以让用户左右切换当前的view. ViewPager特点: ...

  2. Android高手进阶教程(二十八)之---Android ViewPager控件的使用(基于ViewPager的横向相册)!!!

      分类: Android高手进阶 Android基础教程 2012-09-14 18:10 29759人阅读 评论(35) 收藏 举报 android相册layoutobjectclassloade ...

  3. Android实现图片轮显效果——自定义ViewPager控件

    一.问题概述 使用ViewPager控件实现可横向翻页.水平切换图片等效果,但ViewPager需要手动滑动才能切换页面,图片轮显效果的效果本质上就是在ViewPager控件的基础上让它能自动的进行切 ...

  4. 【Android】带底部指示的自定义ViewPager控件

    在项目中经常需要使用轮转广告的效果,在android-v4版本中提供的ViewPager是一个很好的工具,而一般我们使用Viewpager的时候,都会选择在底部有一排指示物指示当前显示的是哪一个pag ...

  5. ViewPager控件的Demo

    1.主视图 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:to ...

  6. duilib中ListCtrl控件的实现

    转载请说明出处,谢谢~~ 昨天在编程群里聊天,提到了ListCtrl,然后有网友找我,他需要做一个ListCtrl控件,我看过需求后接下了这个活.今天就把大致的思路和过程记录一下.首先看<任务书 ...

  7. Design库,所有控件的使用

    导入地址com.android.support:design:23.2.0..输入design搜索到确认就可以. 布局中android.support.design.widget.XXX,调用控件 控 ...

  8. android内部培训视频_第三节(3)_常用控件(ViewPager、日期时间相关、ListView)

    第三节(2):常用控件之ViewPager.日期时间相关.ListView  一.ViewPager 实例:结合PagerAdapter滑动切换图片  二.日期时间相关:AnalogClock\Dig ...

  9. 使用 ViewPager 和 RadioGroup 封装的一个导航控件

    import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.dra ...

随机推荐

  1. WPF 中动态创建、删除控件,注册控件名字,根据名字查找控件

    动态创建控件 1.容器控件.RegisterName("Name",要注册的控件)   //注册控件 2.容器控件.FindName("Name") as  控 ...

  2. javascript笔记5-BOM

    Javascript应用的平台很多,不仅仅针对Web.在Web中使用Javascript,BOM(browser object model,浏览器对象模型)是核心. BOM提供了很多对象,用于访问浏览 ...

  3. 如何在ubuntu 12.04 中安装经典的 GNOME桌面

    这次介绍的是如何在ubuntu 12.04 中安装经典的 GNOME桌面,默认的 Ubuntu 12.04 默认unity桌面,一些用户不喜欢 Unity 桌面,所以想找回昔日的经典Gnome桌面. ...

  4. 黑马程序员——【Java基础】——Java概述

    ---------- android培训.java培训.期待与您交流! ---------- 一.Java语言概述及三大技术架构 1.Java语言概述 Java是SUN公司于1995年推出的一种面向I ...

  5. 链表操作----将单链表向右旋转 K 个位置

    给定一个单链表,设计一个算法实现链表向右旋转 K 个位置. 举例: 给定 1->2->3->4->5->6->NULL, K=3 则     4->5-> ...

  6. BZOJ 1657 奶牛的歌声

    单调栈. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm&g ...

  7. hdoj 2059 :龟兔赛跑 (DP)[转]

      转的别人的找了很多就这个比较好理解.   Problem Description 据说在很久很久以前,可怜的兔子经历了人生中最大的打击——赛跑输给乌龟后,心中郁闷,发誓要报仇雪恨,于是躲进了杭州下 ...

  8. 直接用bat命令对Inno Setup的脚本文件.iss进行编译

    直接用bat命令对Inno Setup的脚本文件.iss进行编译 2010-06-17 15:17 qjn0059 | 浏览 2163 次 编程语言外语学习 分享到:   2010-06-29 11: ...

  9. 第一个Sprint冲刺第七天

    讨论成员:邵家文.李新.朱浩龙.陈俊金 讨论问题:怎样添加功能 讨论地点:宿舍 遇到问题:编写代码的思路不完整,很混乱 工作进度: 队员工作照:

  10. AWK处理日志入门(转)

    前言 这两天自己挽起袖子处理日志,终于把AWK给入门了.其实AWK的基本使用,学起来也就半天的时间,之前总是靠同事代劳,惰性呀. 此文仅为菜鸟入门,运维们请勿围观. 下面是被处理的日志的示例,不那么标 ...