复杂自定义控件---自定义ViewPager的实现

效果图

核心方法

1、三个构造方法(一个参数, 两个参数, 三个参数)

2、onMesure 测量控件

4、onLayout 分配控件布局

5、computeScroll()  
计算滑动

6、onDraw   绘制控件

7、onTouchEvent() 
中断事件传递

8、dispatchTouchEvent 
分发事件

实现步骤:

1   初始化显示的数据

        //为MyViewPager添加图片
        for(int i=0; i<imgs.length; i++) {
            ImageView imageView = new ImageView(getApplicationContext());
            imageView.setBackgroundResource(imgs[i]);
            mMyViewPager.addView(imageView);
        }

        View view = View.inflate(getApplicationContext(), R.layout.ll_view, null);
        mMyViewPager.addView(view, 2);

2 测量控件  (注:由于控件的嵌套复杂性不同,导致系统测量的次数不一样,嵌套布局越多测量                           越复杂,所以在使用布局时尽量避免嵌套的层次)

<strong><span style="color:#ff0000;">//  onMeasure  会在onLayout 之前调用
    // 要求父容器一定要测量子容器 ,如果不测量 子容器 子容器宽和高 都是0   子容器由于挂载到父容器可以正常显示,但是 孙子就不能显示
    // 父容器先知道自己大小(match_parent) 子容器先知道大小(wrap_content)
    //widthMeasureSpec不仅表示控件的宽,里面还带有控件的属性的基本信息</span></strong>
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        System.out.println("onMeasure");
        System.out.println(widthMeasureSpec);
        MeasureSpec.getMode(widthMeasureSpec); //获取控件的模型
        MeasureSpec.getSize(widthMeasureSpec); // 得到控件真正的尺寸
        System.out.println(heightMeasureSpec);
        for(int i=0; i< getChildCount(); i++) {
            View view = getChildAt(i);
            view.measure(widthMeasureSpec, heightMeasureSpec);// 对每个孩子都测量
        }
    }

3  分配控件显示的位置

 //  分配孩子位置     在onDraw方法之前调用
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        for(int i=0; i<getChildCount(); i++) {
            View view = getChildAt(i);
            view.layout(0 + getWidth() * i, 0, getWidth() + getWidth() * i, getHeight());
        }
    }

4   让控件随着手指的移动而移动

//手势识别监听器
    private class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener {
        //滑动事件
        //distanceX x轴滑动的距离
        //distanceY y轴滑动的距离
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                                float distanceX, float distanceY) {
            scrollBy((int)distanceX, 0); //让viewGroup 移动多少距离
            //scrollBy  会自动调用invalidate() 该方法
            //invalidate();   自动调用onDraw
            return super.onScroll(e1, e2, distanceX, distanceY);
        }
    }
 private void initView() {

        mGestureDetector = new GestureDetector(getContext(), new MySimpleOnGestureListener());

    }
@Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event); //把手势识别器注册到触摸事件中
        switch(event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 当手指按下的时候 记录开始的坐标
                startX = (int) event.getX();
                break;
            case MotionEvent.ACTION_UP:
                // 当手指抬起的时候 记录结束的坐标
                int endX = (int) event.getX();

                if((startX - endX) > getWidth() / 2) {
                    //进入下一个界面
                    index++;
                } else if((endX - startX) > getWidth() / 2) {
                    // 进入上一个界面
                    index--;
                }
                moveToIndex();
                break;
            default:
                break;
        }
        //返回处理了触摸事件
        return true;

    }

5 自动跳转界面(根据手势滑动的距离,确定页面跳转)

 private void moveToIndex() {
        if(index < 0) {
            index = 0;
        }
        if(index == getChildCount()) {
            index = getChildCount() -1;
        }
        if(mOnpageChangedListener != null) {
            mOnpageChangedListener.onChange(index);
        }
        mScroller = new Scroller(getContext());
        mScroller.startScroll(getScrollX(), getScrollY(), (int)(getWidth() * index - getScrollX()), 0);
        invalidate();
    }

6 移动(手指抬起时确定要跳转的页面后,慢慢的实现页面移动到指定的位置)

 private void moveToIndex() {
        if(index < 0) {
            index = 0;
        }
        if(index == getChildCount()) {
            index = getChildCount() -1;
        }
        if(mOnpageChangedListener != null) {
            mOnpageChangedListener.onChange(index);
        }
        mScroller = new Scroller(getContext());
        mScroller.startScroll(getScrollX(), getScrollY(), (int)(getWidth() * index - getScrollX()), 0);
        invalidate();
    }

    //计算移动   每次刷新界面 该方法都会被调用
    //scroller.computeScrollOffset()   返回值是true 情况下  代表动作没有结束
    @Override
    public void computeScroll() {
        if(mScroller != null) {
            if(mScroller.computeScrollOffset()) {
                scrollTo(mScroller.getCurrX(), 0);  //scrollTo这个方法一执行 会调用invalidate();,异步执行
                invalidate();
            }
        }
        super.computeScroll();
    }

7 中断事件(当左右移动的控件里嵌套了上下移动的空间--ScrollView 应该判断,当前的手势响应是否被中断,通过判断,当前使用者的意图,确定是左走滑动,还是要上下滑动,来决定是否中断手势事件的向下传递)

//  中断事件传递
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch(ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mGestureDetector.onTouchEvent(ev); // 避免了中断事件 导致没有处理按下的操作
                startX2 = (int) ev.getX();
                startY2 = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE: // 手指移动的事件
                int endX2 = (int) ev.getX();
                int endY2 = (int) ev.getY();
                int dx = endX2 - startX2;  // x轴的偏移量
                int dy = endY2 - startY2;  //y轴的偏移量

                if(Math.abs(dx) > Math.abs(dy)) { //如果为左右移动则中断手势事件响应的传递
                    return true;
                }
                break;
            default:
                break;
        }
        // 如果是上下滑动 屏幕的时候 不中断事件
        //  return false;
        //如果是左右滑动 中断事件
        // return true;
        //交给父类判断(即交给ViewGroup判断)父类的该方法返回值为false 不中断事件
        return super.onInterceptTouchEvent(ev);
    }

android中Touch事件处理流程图:

Touch事件传递机制流程图:

8 回调方法(当跳转到ViewPager中的某一页时,会自动触发某个事件实现接口回调)

// 定义一个公开接口,设置回调方法
    public interface OnPageChangedListener {
        void onChange(int index);
    }

    private OnPageChangedListener mOnpageChangedListener;

    //定义一个公开的注册页面改变的方法
    public void setOnpageChangedListener(OnPageChangedListener listener) {
        mOnpageChangedListener = listener;
    }
private void moveToIndex() {
        if(index < 0) {
            index = 0;
        }
        if(index == getChildCount()) {
            index = getChildCount() -1;
        }
        if(mOnpageChangedListener != null) {
            mOnpageChangedListener.onChange(index);
        }
        mScroller = new Scroller(getContext());
        mScroller.startScroll(getScrollX(), getScrollY(), (int)(getWidth() * index - getScrollX()), 0);
        invalidate();
    }

完整代码:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<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.mhy.zidingyiviewpager.MainActivity">

    <RadioGroup
        android:id="@+id/mRadioGroup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        </RadioGroup>
    <com.example.mhy.zidingyiviewpager.MyViewPager
        android:id="@+id/mViewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
    </com.example.mhy.zidingyiviewpager.MyViewPager>
</LinearLayout>

ll_view.xml

<?xml version="1.0" encoding="utf-8"?>
 <ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" > 

    <LinearLayout

        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button" />

        <EditText
            android:id="@+id/editText1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:inputType="textPersonName" >

            <requestFocus />
        </EditText>

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Medium Text"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Large Text"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Large Text"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/textView4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Large Text"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button" />

        <EditText
            android:id="@+id/editText1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:inputType="textPersonName" >

            <requestFocus />
        </EditText>

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Medium Text"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Large Text"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Large Text"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/textView4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Large Text"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button" />

        <EditText
            android:id="@+id/editText1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:inputType="textPersonName" >

            <requestFocus />
        </EditText>

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Medium Text"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Large Text"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Large Text"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/textView4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Large Text"
            android:textAppearance="?android:attr/textAppearanceLarge" />
    </LinearLayout>

</ScrollView>

MyViewPager.java

package com.example.mhy.zidingyiviewpager;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;

/**
 * Created by mhy on 2016/6/15.
 */
public class MyViewPager extends ViewGroup {

    private GestureDetector mGestureDetector;
    private Scroller mScroller;

    public MyViewPager(Context context) {
        super(context);
        // 创建手势识别器
        initView();
    }

    //  如果没有两个参数构造方法 是不允许在布局文件中声明控件
    public MyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 创建手势识别器
        initView();
    }

    public MyViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 创建手势识别器
        initView();
    }

	//手势识别监听器
    private class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener {
        //滑动事件
        //distanceX x轴滑动的距离
        //distanceY y轴滑动的距离
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                                float distanceX, float distanceY) {
            scrollBy((int)distanceX, 0); //让viewGroup 移动多少距离
            //scrollBy  会自动调用invalidate() 该方法
            //invalidate();   自动调用onDraw
            return super.onScroll(e1, e2, distanceX, distanceY);
        }
    }
    private void initView() {

        mGestureDetector = new GestureDetector(getContext(), new MySimpleOnGestureListener());

    }

    // 定义一个公开接口,设置回调方法
    public interface OnPageChangedListener {
        void onChange(int index);
    }

    private OnPageChangedListener mOnpageChangedListener;

    //定义一个公开的注册页面改变的方法
    public void setOnpageChangedListener(OnPageChangedListener listener) {
        mOnpageChangedListener = listener;
    }

    //  中断事件传递
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch(ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mGestureDetector.onTouchEvent(ev); // 避免了中断事件 导致没有处理按下的操作
                startX2 = (int) ev.getX();
                startY2 = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE: // 手指移动的事件
                int endX2 = (int) ev.getX();
                int endY2 = (int) ev.getY();
                int dx = endX2 - startX2;  // x轴的偏移量
                int dy = endY2 - startY2;  //y轴的偏移量

                if(Math.abs(dx) > Math.abs(dy)) { //如果为左右移动则中断手势事件响应的传递
                    return true;
                }
                break;
            default:
                break;
        }
        // 如果是上下滑动 屏幕的时候 不中断事件
        //  return false;
        //如果是左右滑动 中断事件
        // return true;
        //交给父类判断(即交给ViewGroup判断)父类的该方法返回值为false 不中断事件
        return super.onInterceptTouchEvent(ev);
    }
    private int startX2;
    private int startY2;

    private int index = 0; // 当前显示的位置
    private int startX;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event); //把手势识别器注册到触摸事件中
        switch(event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 当手指按下的时候 记录开始的坐标
                startX = (int) event.getX();
                break;
            case MotionEvent.ACTION_UP:
                // 当手指抬起的时候 记录结束的坐标
                int endX = (int) event.getX();

                if((startX - endX) > getWidth() / 2) {
                    //进入下一个界面
                    index++;
                } else if((endX - startX) > getWidth() / 2) {
                    // 进入上一个界面
                    index--;
                }
                moveToIndex();
                break;
            default:
                break;
        }
        //返回处理了触摸事件
        return true;

    }
    //外界通过指定索引将页面切换到指定的位置
    public void moveToIndex(int index) {
        this.index = index;
        moveToIndex();
    }

    private void moveToIndex() {
        if(index < 0) {
            index = 0;
        }
        if(index == getChildCount()) {
            index = getChildCount() -1;
        }
        if(mOnpageChangedListener != null) {
            mOnpageChangedListener.onChange(index);
        }
        mScroller = new Scroller(getContext());
        mScroller.startScroll(getScrollX(), getScrollY(), (int)(getWidth() * index - getScrollX()), 0);
        invalidate();
    }

    //计算移动   每次刷新界面 该方法都会被调用
    //scroller.computeScrollOffset()   返回值是true 情况下  代表动作没有结束
    @Override
    public void computeScroll() {
        if(mScroller != null) {
            if(mScroller.computeScrollOffset()) {
                scrollTo(mScroller.getCurrX(), 0);  //scrollTo这个方法一执行 会调用invalidate();,异步执行
                invalidate();
            }
        }
        super.computeScroll();
    }

    //  onMeasure  会在onLayout 之前调用
    // 要求父容器一定要测量子容器 ,如果不测量 子容器 子容器宽和高 都是0   子容器由于挂载到父容器可以正常显示,但是 孙子就不能显示
    // 父容器先知道自己大小(match_parent) 子容器先知道大小(wrap_content)
    //widthMeasureSpec不仅表示控件的宽,里面还带有控件的属性的基本信息
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        System.out.println("onMeasure");
        System.out.println(widthMeasureSpec);
        MeasureSpec.getMode(widthMeasureSpec); //获取控件的模型
        MeasureSpec.getSize(widthMeasureSpec); // 得到控件真正的尺寸
        System.out.println(heightMeasureSpec);
        for(int i=0; i< getChildCount(); i++) {
            View view = getChildAt(i);
            view.measure(widthMeasureSpec, heightMeasureSpec);// 对每个孩子都测量
        }
    }

    //  分配孩子位置     在onDraw方法之前调用
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        for(int i=0; i<getChildCount(); i++) {
            View view = getChildAt(i);
            view.layout(0 + getWidth() * i, 0, getWidth() + getWidth() * i, getHeight());
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }
}

MainActivity.java

package com.example.mhy.zidingyiviewpager;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RadioGroup;

public class MainActivity extends AppCompatActivity {

    private MyViewPager mMyViewPager;
    private RadioGroup mRadioGroup;

    private int[] imgs = new int[] { R.mipmap.a1, R.mipmap.a2, R.mipmap.a3,
            R.mipmap.a4, R.mipmap.a5, R.mipmap.a6};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mMyViewPager = (MyViewPager) findViewById(R.id.mViewPager);
        mRadioGroup = (RadioGroup) findViewById(R.id.mRadioGroup);

        //为MyViewPager添加图片
        for(int i=0; i<imgs.length; i++) {
            ImageView imageView = new ImageView(getApplicationContext());
            imageView.setBackgroundResource(imgs[i]);
            mMyViewPager.addView(imageView);
        }

        View view = View.inflate(getApplicationContext(), R.layout.ll_view, null);
        mMyViewPager.addView(view, 2);
        System.out.println("mMyViewPager.getChildCount() " + mMyViewPager.getChildCount());

        for(int i=0; i<mMyViewPager.getChildCount(); i++) {

            RadioButton radioButton = new RadioButton(getApplicationContext());
            radioButton.setId(i);
            mRadioGroup.addView(radioButton);

            if(i == 0) {
                radioButton.setChecked(true);
            }
        }

        //监听页面切换事件,使对应的单选按钮做相应的改变
        mMyViewPager.setOnpageChangedListener(new MyViewPager.OnPageChangedListener() {

            @Override
            public void onChange(int index) {
                RadioButton radioButton = (RadioButton) mRadioGroup.getChildAt(index);
                radioButton.setChecked(true);
            }
        });

        //监听单选按钮更改的事件,使ViewPager页面更随做相应的切换
        mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                mMyViewPager.moveToIndex(checkedId);
            }
        });

    }
}
时间: 2024-10-20 16:58:24

复杂自定义控件---自定义ViewPager的实现的相关文章

Android 自定义 ViewPager 打造千变万化的图片切换效果

Android 自定义 ViewPager 打造千变万化的图片切换效果 标签: Android自定义ViewPagerJazzyViewPager 目录(?)[+] 转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38026503 记 得第一次见到ViewPager这个控件,瞬间爱不释手,做东西的主界面通通ViewPager,以及图片切换也抛弃了ImageSwitch之类的,开 始让ViewPager来做.时间长了,ViewPa

三行代码接入,社交软件打字时底下弹出的表情布局,自定义ViewPager+页面点标+各种功能的android小框架。

(转载请声明出处:http://www.cnblogs.com/linguanh/) 前言: 接上次分享的 ListView 动态加载类,入口:http://www.cnblogs.com/linguanh/p/4645115.html  这次分享给大家的是,刚些写好的类似社交软件打字时地下弹出的表情布局. 先看下我的默认效果图. 该效果图里面使用的图片资源,是默认的IC_lanucher,在我的类里面,你可以自定义,包括布局,几行几列,什么的,都可以自定义.底下的是小点标. 下集预告:我将在使

【转】android 自定义ViewPager,修改原动画

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38026503 记 得第一次见到ViewPager这个控件,瞬间爱不释手,做东西的主界面通通ViewPager,以及图片切换也抛弃了ImageSwitch之类的,开 始让ViewPager来做.时间长了,ViewPager的切换效果觉得枯燥,形成了审美疲劳~~我们需要改变,今天教大家如何改变ViewPager 切换时的效果,实现个性化的图片切换~~ 看一下这样效果的图片切换: 是

Android为ViewPager增加切换动画——自定义ViewPager

转载请注明出处:http://blog.csdn.net/allen315410/article/details/44224517 在上篇博客中,我写了一个使用属性动画为ViewPager添加切换动画的方法,并且可以兼容到Android3.0以下版本的设备上,那么关于为ViewPager添加动画的方式还会有另外一种实现方案,就是自定义一个自己带动画效果的ViewPager,关于上篇博客,还没来得及查看的朋友可以点击这里进行查看.下面,我们将新建一个工程,来说说怎样自定义一个自带切换动画效果的Vi

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

一.问题概述 使用ViewPager控件实现可横向翻页.水平切换图片等效果,但ViewPager需要手动滑动才能切换页面,图片轮显效果的效果本质上就是在ViewPager控件的基础上让它能自动的进行切换,所以实现图片轮显步骤如下: 1.  扩展ViewPager自定义一个MyScrollImageView类 2.  为MyScrollImageView定义适配器,装载图片信息 3.  定义图片滑动动画时间控制类 接下来我们就一步步实现下图案例: 二.实现套路 1.为自定义ViewPager控件编

自定义ViewPager的导航indecator(非常实用和主流)

自定义ViewPager的导航indecator(非常实用和主流) 现在很多App的欢迎页或者主页的轮播下面都有indicator(就是那个随着viewpager滚动而跟着滚动的小圆点):然后很多显示效果基本就是放一个选中的图片和一个未选择的图片,让这两个图片不断的轮换,这个效果都是烂大街了.而有一种效果就是那个选中的小圆点是随着viewpager的滑动而滑动有明显的动画效果,我就琢磨着怎样做这样一个效果,果不起然,功夫不负有心人,终于弄出来了,效果如下: 先制作一个草稿图如下: 要考虑的技术点

千变万化的ViewPager切换动画(2)--自定义ViewPager的实现方法

(1)创建项目Viewpager_anim_myself 都采用默认的方式,添加三张图片资源文件,src-包目录下创建MyViewPagerTransformerAnim.java类 布局文件activity_main.xml如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools

Android自定义ViewPager(一)——自定义Scroller模拟动画过程

转载请注明出处:http://blog.csdn.net/allen315410/article/details/41575831 相信Android SDK提供的ViewPager组件,大家实在是熟悉不过了,但是ViewPager存在于support.v4包下的,说明ViewPager并不存在于早期的android版本中,那么如何在早期的android版本中也同样使用类似于ViewPager一样的滑动效果呢?这里,我们还是继续探讨一下andrid的自定义组件好了,并且这篇博文只探讨androi

自定义控件——自定义视图属性

一.新建工程 二.创建类并继承View package com.example.l01myrect; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.View; /** * Created by 袁磊 on 2017/2/6. */ public class MyRect extends View