zoukankan      html  css  js  c++  java
  • 自定义view-仿网易音乐播放的按键

    上图:

    上代码:

    package com.example.testview;
    
    import android.annotation.SuppressLint;
    import android.annotation.TargetApi;
    import android.content.Context;
    import android.os.Build;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.animation.LinearInterpolator;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    import android.support.v4.view.MotionEventCompat;
    import android.support.v4.view.ViewCompat;
    
    @SuppressLint("NewApi")
    public class MusicView extends LinearLayout {
    
        public MusicView(Context context, AttributeSet attrs, int defStyleAttr,
                int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
            // TODO Auto-generated constructor stub
        }
    
        @TargetApi(Build.VERSION_CODES.HONEYCOMB)
        public MusicView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            // TODO Auto-generated constructor stub
        }
    
        public MusicView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initView(context);
        }
    
        public MusicView(Context context) {
            super(context);
            // TODO Auto-generated constructor stub
        }
    
        private void initView(Context mContext) {
            this.setClickable(true);
            initLine(mContext);
        }
    
        int lineNum = 4;
        int lineW = 5;
        TextView[] lines;
        LinearLayout.LayoutParams[] lps;
        int lineBgNomal = 0xFF000000;
        int lineBgClick = 0xFFFFFFFF;
    
        private void initLine(Context mContext) {
            if (lines == null) {
                lines = new TextView[lineNum];
                lps = new LinearLayout.LayoutParams[lineNum];
                for (int i = 0; i < lines.length; i++) {
                    lines[i] = new TextView(mContext);
                    lines[i].setBackgroundColor(lineBgNomal);
                    lps[i] = new LinearLayout.LayoutParams(lineW,
                            LinearLayout.LayoutParams.MATCH_PARENT);
                    lps[i].weight = 1;
                }
            }
        }
    
        private void setLineBg(int color) {
            if (lines != null)
                for (int i = 0; i < lines.length; i++) {
                    lines[i].setBackgroundColor(color);
                }
        }
    
        int mHeight;
        int mWidth;
    
        boolean isNeedRelayoutLines = true;
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int height = getMeasuredHeight();
            int width = getMeasuredWidth();
            if (height > 0) {
                mHeight = height;
            }
            if (width > 0) {
                mWidth = width;
            }
            if (isNeedRelayoutLines && mWidth > 0 && isShowToWindow) {
    
                int lPad = getPaddingLeft();
                int rPad = getPaddingRight();
                float perW = (mWidth - (lPad + rPad)) * 1.0f / lineNum;
                int marginW = (int) ((perW - lineW) / 2);
                for (int i = 0; i < lines.length; i++) {
                    lps[i].leftMargin = lps[i].rightMargin = marginW;
                    addView(lines[i], lps[i]);
                }
                isNeedRelayoutLines = false;
                invalidate();
    
                startMoveAnimation();
            }
        }
    
        boolean isShowToWindow = false;
    
        @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
            isShowToWindow = true;
        }
    
        @Override
        protected void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            isShowToWindow = false;
            isNeedRelayoutLines = true;
        }
    
        boolean isTouched = false;
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            final int action = MotionEventCompat.getActionMasked(event);
    
            Log.e("mytag", "<<" + action);
            
            switch (action) {
            case MotionEvent.ACTION_DOWN:
    
                if (!isTouched) {
                    isTouched = true;
                    setLineBg(lineBgClick);
                    invalidate();
                }
    
                break;
    
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                if (isTouched) {
                    isTouched = false;
                    setLineBg(lineBgNomal);
                    invalidate();
                }
                break;
            }
    
            return super.onTouchEvent(event);
        }
    
        // ----------------
        // move
        // ----------------
        private void setLineMovePercent(TextView line, float percent) {
            int topPad = getPaddingTop();
            int bottomPad = getPaddingBottom();
            int LineHeight = mHeight - (topPad + bottomPad);
            int margintop = (int) ((1 - percent) * LineHeight);
            LinearLayout.LayoutParams ll = (LayoutParams) line.getLayoutParams();
            ll.topMargin = margintop;
            line.setLayoutParams(ll);
        }
    
        class LineMoveAnimationRunable implements Runnable {
    
            long startTime;
            long curTime;
            long durationTime;
            float startPercent;
            float toPercent;
            TextView line;
            MoveAnimationEndListener mMoveAnimationEndListener;
    
            public LineMoveAnimationRunable(TextView line, float startPercent,
                    float toPercent, long durationTime,
                    MoveAnimationEndListener mMoveAnimationEndListener) {
                this.durationTime = durationTime;
                this.startPercent = startPercent;
                this.toPercent = toPercent;
                this.line = line;
                this.mMoveAnimationEndListener = mMoveAnimationEndListener;
            }
    
            @Override
            public void run() {
    
                if (startTime == 0) {
                    startTime = System.currentTimeMillis();
                }
    
                curTime = System.currentTimeMillis();
    
                float percent = (curTime - startTime) * 1.0f / durationTime;
    
                LinearInterpolator linearInterpolator = new LinearInterpolator();
    
                float dpercent = linearInterpolator.getInterpolation(percent);
    
                float mpercent = startPercent;
    
    //            Log.e("mytag", "<<" + dpercent);
    
                if (startPercent < toPercent) {// 增加
    
                    mpercent = startPercent + dpercent;
    
                    if (mpercent >= toPercent) {
                        mpercent = toPercent;
                    }
                } else {
    
                    mpercent = startPercent - dpercent;
    
                    if (mpercent <= toPercent) {
                        mpercent = toPercent;
                    }
                }
    
                if (!isShowToWindow) {
                    return;
                }
    
                setLineMovePercent(line, mpercent);
                invalidate();
    
                if (mpercent == toPercent) {
                    if (mMoveAnimationEndListener != null) {
                        mMoveAnimationEndListener.AnimationEnd(line, startPercent,
                                toPercent, durationTime);
                    }
                    return;
                } else {
                    line.postDelayed(this, 50L);
                }
            }
        }
    
        interface MoveAnimationEndListener {
            public void AnimationEnd(TextView line, float startPercent,
                    float toPercent, long durationTime);
        }
    
        public void startMoveAnimation() {
            // 0 2 0.5 -1
            // 1 3 1-0.5
            MoveAnimationEndListener listener = new MoveAnimationEndListener() {
                @Override
                public void AnimationEnd(TextView line, float startPercent,
                        float toPercent, long durationTime) {
                    LineMoveAnimationRunable moveRunnable = new LineMoveAnimationRunable(
                            line, toPercent, startPercent, durationTime, this);
                    line.postDelayed(moveRunnable, 200L);
                }
            };
    
            for (int i = 0; i < lines.length; i++) {
                if (i % 2 == 0) {
                    LineMoveAnimationRunable moveRunnable = new LineMoveAnimationRunable(
                            lines[i], 0.5f, 1.0f, 1000L, listener);
                    lines[i].post(moveRunnable);
                } else {
                    LineMoveAnimationRunable moveRunnable = new LineMoveAnimationRunable(
                            lines[i], 1f, 0.5f, 1000L, listener);
                    lines[i].post(moveRunnable);
                }
            }
        }
    }

    遗留问题:如上 每个line是单独的线程  可优化为四个line setMargin之后统一invalidate 

    自定义控件总结 

    几个相关函数:

    1.构造函数:   初始化view ,获取自定义属性

    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RefreshView);
            final int type = a.getInteger(R.styleable.RefreshView_type, STYLE_SUN);
    

    2.onMeasure函数 中获取measure后的宽高

    int height = getMeasuredHeight();
    int width = getMeasuredWidth();

    调用子view的 measure函数,

    MeasureSpec.EXACTLY 父类指定大小 
    AT_MOST 子类尽可能大
    UNSPECIFIED 未指定大小
    widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingRight() - getPaddingLeft(), MeasureSpec.EXACTLY);
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY);
            mTarget.measure(widthMeasureSpec, heightMeasureSpec);
            mRefreshView.measure(widthMeasureSpec, heightMeasureSpec);
    

    3.onLayout函数布局 调用 子view的layout 函数布局

     protected void onLayout(boolean changed, int l, int t, int r, int b) {
          ... ...
            int height = getMeasuredHeight();
            int width = getMeasuredWidth();
            int left = getLeft();
            int top = getTop();
            int right = getRight();
            int bottom = getBottom();
    
            int lpad = getPaddingLeft();
            int rpad = getPaddingRight();
            int tpad = getPaddingTop();
            int bpad = getPaddingBottom();
    
            mTarget.layout(left + lpad, top + tpad+ mCurrentOffsetTop, right-rpad, bottom-bpad + mCurrentOffsetTop);
            mRefreshView.layout(left, top, left + width - right, top + height - bottom);
        }

    4.onInterceptTouchEvent 拦截touch事件  主要做状态的改变检测  

     onTouchEvent 主要touch逻辑操作 计算滑动距离等 改变子类view 需调用 this.validate or  this. postvalidate

      改变自身需要父类控件重新布局需要调用 requireLayout

    5.动画相关 如 拖拽完成后的动画复位 Animation类 或者 Runnable类

         mAnimateToStartPosition.reset();
            mAnimateToStartPosition.setDuration(animationDuration);
            mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator);
            mAnimateToStartPosition.setAnimationListener(mToStartListener);
            mRefreshView.clearAnimation();
            mRefreshView.startAnimation(mAnimateToStartPosition);
    

      

    private final Animation mAnimateToStartPosition = new Animation() {
            @Override
            public void applyTransformation(float interpolatedTime, Transformation t) {
                moveToStart(interpolatedTime);
            }
        };
    

      interpolateTime 时间所对应的差值点

  • 相关阅读:
    My97日期控件 My97 DatePicker 4.0 Prerelease 发布
    My97DatePicker提问需知,仔细阅读可以在最快的时间收到问题反馈
    My97日期控件3.0不支持IE8,4.2以上已经支持,强烈建议还在使用3.x的用户换成最新版
    My97日期控件 My97 DatePicker 4.0 Beta4 发布(候选版本)
    My97日期控件 My97 DatePicker 4.0 正式版
    坚持打造最好的日期控件,My97 DatePicker 4.7 Release
    [PYTHON] 格式化输出的几种方法 HONG
    数组反转函数 blog_zss小帅
    fastadmin 按钮状态 blog_zss小帅
    fastadmin 固定列表字段 blog_zss小帅
  • 原文地址:https://www.cnblogs.com/wjw334/p/4342504.html
Copyright © 2011-2022 走看看