Android学习——自定义利用Scroller实现可循环滚动的动画菜单控件(功能完善待改进)

本文介绍了一种简单易懂的Android自定义View实现,即一个可循环滚动的动画菜单控件。通过继承LinearLayout并使用Scroller,作者展示了如何创建横向和纵向滚动的菜单,并详细讲解了关键代码,包括onMeasure、startAnimation、onLayout、onInterceptTouchEvent和computeScroll等方法。尽管存在一些小bug,但作者计划在未来进行改进。
摘要由CSDN通过智能技术生成

       都说自定义View是小白和中级开发者的分界线,这也看出来自定义View在Android开发过程中的重要性,所以我的博客初期会以各种各样的自定义View为主。不会讲述太多的原理,主要提供一种简单易懂的实现。

        本期要实现的是可循环拉动的动画菜单。这个控件我在其他博客上看到过不少的实现方法,但是大多数要么就是代码量太大,要么就是结构太复杂,对新手来说阅读和理解起来比较困难,所以我今天花了一些时间来实现一个简单可用的循环滚动菜单控件。

        先看看效果图,这种控件提供了横向和纵向的实现

      

      接下来进行代码讲解

      代码主要是继承LinearLayout来实现的ScrollerLayout,共有21个方法,当其中只有5个是重要的,其他都是些数值设置初始化相关的方法。下面先来看看自定义的变量

/**
     * 公用的变量
     */
    private Context myContext;//上下文变量
    private Scroller mScroller;//用于操控滚动的Scroller变量
    private int mTouchSlop;//用于判断触碰操作是点击还是滚动
    private int itemPadding;//子元素间距
    private int moveDirection;//点击移动的方向
    private int mOrientation;//布局方向
    private int visiableItemNum;//屏幕可见的子元素个数
    private ArrayList<View>  childViewList;//子元素列表
    private int next;//下一个要显示的子元素索引
    private int front;//上一个要显示的子元素索引
    private int totalNum;//全部子元素个数
    /**
     * LinearLayout为横向时使用的变量
     */
    private float mXDownPos;//点击位置的x坐标
    private float mXMovePos;//点击并移动后的x坐标
    private float mXLastMovePos;//上一次触发滑动事件的位置
    private int leftBorder;//左界限
    private int rightBorder;//右界限
    private int width;//屏幕宽度
    private int displayWidth;//显示的子元素的宽度
    /**
     * LinearLayout为纵向时使用的变量
     */
    private int height;//屏幕高度
    private float mYDownPos;//点击位置的y坐标
    private float mYMovePos;//点击并移动后的y坐标
    private float mYLastMovePos;//上一次触发滑动事件的位置
    private int topBorder;//上界限
    private int bottomBorder;//下界限
    private int displayHeight;//显示的子元素的高度
    private int statusBarHeight;//状态栏高度
    private int titleBarHeight;//标题栏高度
    private int navigationBarHeight;//底部导航栏(部分Android手机的按键高度也属于导航栏高度)

      之前说过这个控件提供了横向和纵向的功能,只需要在XML布局文件中将android:orientation进行设置即可。下面的是所有与数值处理有关的方法,共16个

  /**
     * 构造函数
     */
    public ScrollerLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setGravity(Gravity.CENTER_VERTICAL);
        this.myContext=context;
        init();
    }
    /**
     * 初始化
     */
    public void init(){
        this.mScroller = new Scroller(this.myContext);//创建Scroller实例
        ViewConfiguration configuration = ViewConfiguration.get(this.myContext);//获取TouchSlop值
        this.mTouchSlop = configuration.getScaledTouchSlop();
    }
    /**
     * 设置屏幕上可见的子元素个数
     * @param value
     */
    public void initVisiableItemNum(int value){
        this.visiableItemNum=(value==0)?getChildCount():value;
        initTotalNum();//获取子元素总个数
        initFront();//获取上一个要显示的子元素索引
        initNext();//获取下一个要显示的子元素索引
    }
    /**
     * 获得子元素列表
     */
    private void initChildViewList(){
        this.childViewList=new ArrayList<View>();
        int childCount = getChildCount();//获取包含的子元素的个数
        for (int i = 0; i < childCount; i++) {
            this.childViewList.add(getChildAt(i));
        }
    }
    /**
     * 初始化状态栏高度
     */
    private void initStatusBarHeight(){
        int result = 0;
        int resourceId = this.myContext.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            result = this.myContext.getResources().getDimensionPixelSize(resourceId);
        }
        this.statusBarHeight=result;
    }
    /**
     * 初始化导航栏高度
     */
    private void initNavigationBarHeight(){
        int result=0;
        Resources resources = this.myContext.getResources();
        int resourceId=resources.getIdentifier("navigation_bar_height","dimen","android");
        if(resourceId!=0)
            this.navigationBarHeight = resources.getDimensionPixelSize(resourceId);
    }
    /**
     * 初始化标题栏高度
     */
    private void initTitleBarHeight(){
        TypedValue tv = new TypedValue();
        if (this.myContext.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
            this.titleBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, this.myContext.getResource
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值