自定义控件ViewPager

效果图:


image.png

MainActivity

package com.example.administrator.viewgroup_xianxi;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
//scrollToPager(id);
public class MainActivity extends Activity {
    private MyviewGroup ViewGroupText;

int dis[]={R.drawable.kkkk, R.drawable.kkkkkk,R.drawable.aaaa};
    private RadioGroup rgMain;




    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ViewGroupText = (MyviewGroup) findViewById(R.id.ViewGroup_text);
        rgMain = (RadioGroup) findViewById(R.id.rg_main);

        for (int i = 0;  i < dis.length; i++) {
            ImageView imageView = new ImageView(this);
            imageView.setBackgroundResource(dis[i]);
            ViewGroupText.addView(imageView);
        }
        //因为加载的是一个布局所以布局里面的控件要进行测量大小
        View addb=View.inflate(this,R.layout.addb,null);
        ViewGroupText.addView(addb,1);

        for (int i = 0; i < ViewGroupText.getChildCount(); i++) {
            RadioButton button=new RadioButton(this);
            button.setId(i);//0-3id
            if(i==0){
                button.setChecked(true);
            }
            rgMain.addView(button);
        }

        //设置RadioGroup选中的变化
        rgMain.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, int id) {
                //MyviewPager
                ViewGroupText.scrollToPager(id);//根据下表定位到具体页面;罪上面
            }
        });
        ViewGroupText.setOnpagerChanglistenter(new MyviewGroup.OnpagerChanglistenter() {
            @Override
            public void onScrollToPager(int position) {
                rgMain.check(position);
            }
        });

    }

}

main布局.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:cheng="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <RadioGroup
        android:id="@+id/rg_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal"></RadioGroup>

    <com.example.administrator.viewgroup_xianxi.MyviewGroup
        android:id="@+id/ViewGroup_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </com.example.administrator.viewgroup_xianxi.MyviewGroup>
</LinearLayout>

自定义MyviewGroup类

package com.example.administrator.viewgroup_xianxi;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;
import android.widget.Toast;

public class MyviewGroup extends ViewGroup {
    int currentIndx;//当前的坐标
    private Scroller mScrolier;
    /**
     * 手势适配器
     * 1,定义出来
     * 2,实例化-把想要的方法给重新
     * 3,在ontouchEvent()把事件钻地给手势识别器
     *
     */
    private GestureDetector mGestureDetector;


    public MyviewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    private void initView(final Context context) {
        mScrolier=new Scroller(context);
        //2,实例化-把想要的方法给重新
        mGestureDetector=new GestureDetector(context,new GestureDetector.SimpleOnGestureListener(){
            @Override
            public void onLongPress(MotionEvent e) {
                Toast.makeText(context, "长安", Toast.LENGTH_SHORT).show();
                super.onLongPress(e);
            }
            /**
             * @param e1//e1按下
             * @param e2//e2离开
             * @param distanceX 在x轴滑动了距离
             * @param distanceY 在Y轴滑动了距离
             * @return
             */
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                //区别
                //scrollTo相对于view的初始位置移动,所以这里view无论点击多少次,都只会相对于view的初始位置移动一定距离。
                //mLayout.scrollTo(getResources().getDimensionPixelSize(R.dimen.a), getResources().getDimensionPixelSize(R.dimen.b));
                //scrollBy相对于view的当前位置移动,所以此处view是每点击一次就向右下角移动一次的。
                //mLayout.scrollBy(getResources().getDimensionPixelSize(R.dimen.a), getResources().getDimensionPixelSize(R.dimen.b));


                //让自己内容移动(不是让孩子移动)
                //根据当前位置移动:getScrollY初始值
                //x:要在x轴平移的距离
                //y:要在y轴移动的距离
                //看点
                //理解相对论(右移动是负)|(左移动是正)
                Log.e("hh", "onScroll: "+distanceX );
                scrollBy((int)distanceX,getScrollY());
                return super.onScroll(e1, e2, distanceX, distanceY);
            }

            @Override
            public boolean onDoubleTap(MotionEvent e) {
                Toast.makeText(context, "双击", Toast.LENGTH_SHORT).show();
                return super.onDoubleTap(e);
            }
        });
    }


    @Override
    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
    //便利孩子,给每个孩子指定在屏幕的坐标位置
        for (int j = 0; j < getChildCount(); j++) {
            View childAt = getChildAt(j);
            //l距离左边距离t距离top上边距离,(一个上点)|r距离左(一个下点)b距离上面
            childAt.layout(j*getWidth(),0,(j+1)*getWidth(),getHeight());
        }
    }
    //判断触摸事件的传递(我只要x轴用来滑倒下一页)

    //如果当前,方法返回true,拦截事件,将会触发当前控件的onTouchEvent()方法
    //如果当前,方法返回false,不拦截事件,事件继续传递给孩子
    //拦截事件
    private float mStarX;
    private float mStarY;


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //因为我在这做了一点滑动判断所以哪一点也需要传入手指适配器不来会跳一下
        mGestureDetector.onTouchEvent(ev);
        boolean issorllX=false;
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN://按下
                //1,记录按下的xy值
                mStarX = ev.getX();
                mStarY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE://移动
                //2,记录结束xy值
               float endX = ev.getX();
                float endY = ev.getY();
                //3,计算绝对值
                float distanceX  =Math.abs(mStarX-endX);
                float  distanceY  =Math.abs(mStarY-endY);
                if(distanceX>distanceY&&distanceX>10){
                    issorllX= true;
                }else{
                    scrollToPager(currentIndx);
                }
                break;
            case MotionEvent.ACTION_UP://抬起
                break;
        }

        return issorllX;
    }

    private float startX;
//    getX()是表示Widget相对于自身左上角的x坐标
//    而getRawX()是表示相对于屏幕左上角的x坐标值(注意:这个屏幕左上角是手机屏幕左上角,不管activity是否有titleBar或是否全屏幕),getY(),getRawY()一样的道理
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        //3,在ontouchEvent()把事件钻地给手势识别器
        mGestureDetector.onTouchEvent(event);
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN://按下
                //1记录坐标
                startX=event.getX();
                break;
            case MotionEvent.ACTION_MOVE://移动
                break;
            case MotionEvent.ACTION_UP://抬起
                //2来到新坐标
                float endx=event.getX();
                //下表位置

                int tempIndex=currentIndx;
                if((startX-endx)>getWidth()/2){
                    //显示下一个页面
                    tempIndex++;
                }else if ((endx-startX)>getWidth()/2){
                    //显示上一个页面
                    tempIndex--;
                }
                scrollToPager(tempIndex);
                break;
        }
            return true;
    }
//屏蔽非法值 根据位置移动到指定页面
    public void scrollToPager(int tempIndex) {
        if(tempIndex<0){
            tempIndex=0;
        }
        if(tempIndex>getChildCount()-1){
            tempIndex=getChildCount()-1;
        }
        //当前页面的下标位置
        currentIndx=tempIndex;
        //distanceX就是滑动时的剩余距离
        int distanceX=currentIndx*getWidth()-getScrollX();
        if(mOnpagerChanglistenter!=null){
            mOnpagerChanglistenter.onScrollToPager(currentIndx);
        }
        //移动到指定的位置
//        scrollTo(currentIndx*getWidth(),getScrollY());
//        mScrolier.startScroll(getScrollX(),getScrollY(),distanceX,0);
        mScrolier.startScroll(getScrollX(),getScrollY(),distanceX,0,Math.abs(distanceX));
        invalidate();//onDraw();computeScroll()
    }
    private OnpagerChanglistenter mOnpagerChanglistenter;
    //让使用者传递接口的实例过来
    public void setOnpagerChanglistenter(OnpagerChanglistenter l){
        mOnpagerChanglistenter=l;
    }
    //监听页面的改变
    //定义接口
    public interface OnpagerChanglistenter{
        //当页面改变的时候回掉这个方法position当前页面的下表
        void onScrollToPager(int position);
    }

    @Override
    public void computeScroll() {
        if(mScrolier.computeScrollOffset()){
            float currX = mScrolier.getCurrX();
            Log.e("hh", "computeScroll: "+currX );
            scrollTo((int)currX,0);
            invalidate();//onDraw();computeScroll()
        }
    }
    //onLayout设置每个孩子在当前的位置大小
    //但如果孩子是布局的话,没有给的控件测量大小,因控件没有测量大小所以就不会显示出来
    //遍历孩子,给每个孩子指定在屏幕的坐标位置
    //获取每一个View孩子进行测量(如布局:目的就是让他的孩子也执行onMeasure测量)
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        for (int i = 0; i < getChildCount(); i++) {
            View chid=getChildAt(i);
            //如果孩子是ViewGroup那么就会进去测量ViewGroup的孩子View
            chid.measure(widthMeasureSpec,heightMeasureSpec);
        }
    }
    //测量onMeasure()说明: lt点(左上)|rb点(右下)  宽度: 右边的距离减掉左边的距离
    //                                         高度: 底部的距离减掉顶部的距离

    /**
     * 1. 测量的时候测量多次
     * 2. widthMeasureSpec父层视图给当前视图的宽和模式
     * 系统的onMeasure所干的事:
     * 1, 根据widthMeasureSpec求得宽度,和父类view给的模式(高以此类推)
     * 2, 根据自身的宽度width,和自身的padding  值,相减(减去两边){父类的宽带减去padding值},求得子View可以拥有的宽度newWidth
     * 3, 根据newWidth和模式求得一个新的MeasureSpec值:
     * MeasureSpec.makeMeasureSpec(newSize,newmode);
     * 用新的MeasureSpec来计算View
     *
     */

}

上面打完就完成了效果(下面是对慢慢滑动计算的类)

package com.example.administrator.viewgroup_xianxi;

import android.os.SystemClock;

public class MyScroller {
    //起始坐标
    private long totTime=500;
    private float scrollX;
    private float scrollY;
    //移动的距离
    private int distanceX;
    private int distanceY;
    //kaijishijian
    private long startTime;
    //是否移动完成
    private boolean isFinish;
    private float mCurrX;
    //得到坐标
    public float getCurrX() {
        return mCurrX;
    }
    public void startScroll(float scrollX, float scrollY, int distanceX, int distanceY) {
        this.scrollX=scrollX;
        this.scrollY=scrollY;
        this.distanceX=distanceX;
        this.distanceY=distanceY;
        this.startTime= SystemClock.uptimeMillis();//体统开机时间
        this.isFinish=false;
    }
    //true正在移动
    //fles移动结束
    public boolean computeScrollOffset(){
        if(isFinish){
            return false;
        }
        long endTime=SystemClock.uptimeMillis();
        //这一小段所发挥的时间
        long passTime=endTime-startTime;
        if(passTime<totTime){
            //还没有移动结束
            //计算平均速度
//            float voleCity=distanceX/totTime;
            //移动这一小段对应的距离
            float distanceSamllx=passTime*distanceX/totTime;
            mCurrX = scrollX + distanceSamllx;

        }else{
            //移动结束
            isFinish=true;
            mCurrX = scrollX + distanceX;
        }



        return true;
    }
}

位置理解图


IMG_0660.PNG
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容