自定义控件是开发中经常使用的技术。系统中自带的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. jQuery tab plugin

    /* www.keleyi.com/ */ ; (function ($) { $.fn.extend({ Tabs: function (options) { // 处理参数 options = $ ...

  2. 解决win7资源监视器不能开启

    刚开始时是这样,点击开始监控,无效 需要开始服务即可解决

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

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

  4. 极客DIY:RFID飞贼打造一款远距离渗透利器

    本文使用最新的渗透工具RFID飞贼(Tastic RFID Thief)和RFID感应破解技术来获取一些拥有安防的建筑物的访问权限. Tastic RFID Thief是一个无声远距离RFID读卡器, ...

  5. 《view programming guide for iOS 》之可以使用动画效果的属性

    frame—Use this to animate position and size changes for the view.  ,框架,可以视图动态改变大小和位置 bounds—Use this ...

  6. yii2 利用小部件生成后台左边菜单栏

    ************   模型层递归查询权限   ************ /**     * 递归方式查询权限     */    public function getPrivilege()  ...

  7. Generic method return type

    Here's the Animal class: public class Animal{ private Map<String,Animal> friends =new HashMap& ...

  8. MVC中Asp.Net管道(二)

    Asp.Net管道: 1.在工作进程w3wp.exe中,利用asp.net_isapi加载.NET运行时,6.0中引入了应用程序池的概念,一个工作进程对应的一个应用程序池.一个应用呢程序池可以加载一个 ...

  9. Zipper_DP

    Description Given three strings, you are to determine whether the third string can be formed by comb ...

  10. 爆破vcrkme01(已补上注册机)

    系统 : Windows xp 程序 : vcrkme01 程序下载地址 :http://pan.baidu.com/s/1mh1n33y 要求 : 爆破 使用工具 :OD 可在“PEDIY Crac ...