zoukankan      html  css  js  c++  java
  • 向上滚动公告栏

    向上滚动公告栏

    项目中需要用到类似公告栏的控件,能用的基本不支持多行显示,于是只好自己动手,苦于没有自定义过一个像样的控件,借鉴Android公告条demo,实现了多行向上滚动的控件。在原控件基础之上添加如下功能:

    • 传入数据分页显示
    • 添加Left Drawable
    • 手指触摸事件处理
    • 添加3D动画翻滚效果

    效果图

    效果图

    源码

    package com.android.view;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Camera;
    import android.graphics.Matrix;
    import android.graphics.Paint;
    import android.graphics.drawable.Drawable;
    import android.os.Handler;
    import android.os.Looper;
    import android.text.TextPaint;
    import android.text.TextUtils;
    import android.util.AttributeSet;
    import android.util.TypedValue;
    import android.view.Gravity;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.animation.AccelerateInterpolator;
    import android.view.animation.AlphaAnimation;
    import android.view.animation.Animation;
    import android.view.animation.AnimationSet;
    import android.view.animation.Transformation;
    import android.view.animation.TranslateAnimation;
    import android.widget.FrameLayout;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    import com.sd2w.market.client.R;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
    import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
    
    /**
     * 公告滚动区
     *
     * @author 祁连山
     * @version 1.0
     * @date 2016-08-17
     */
    
    public class RollingView extends FrameLayout implements OnClickListener {
    
        // 默认动画执行时间
        private static final int ANIMATION_DURATION = 1000;
    
        // 延迟滚动时间间隔
        private long mDuration = 3000;
        // 字体颜色
        private int mTextColor = 0xff000000;
        // 点击后字体颜色
        private int mClickColor = 0xff0099ff;
        // 字体大小
        private float mTextSize = 14;
        // 行间距
        private int mTextPadding = 10;
        // 画笔
        private Paint mPaint;
        // 默认每页信息数
        private int mPageSize = 3;
        // 最后一页余数
        private int mUpLimited = mPageSize;
        // 当前显示页码
        private int mCurrentPage = 0;
        // 总分页数
        private int mPageCount;
        // 左图片
        private int mLeftDrawable;
        // 分页数据对象
        private List<LinearLayout> mRollingPages;
        // 默认动画
        private AnimationSet mEnterAnimSet;
        private AnimationSet mExitAnimSet;
        private RollingRunnable mRunnable;
        private Handler mHandler;
        private onItemClickListener mClickListener;
        // 布局参数
        private LayoutParams mFrameParams;
        private LinearLayout.LayoutParams mLinearParams;
        //mEnterDownAnim,mOutUp分别构成向下翻页的进出动画
        private Rotate3dAnimation mEnterDownAnim;
        private Rotate3dAnimation mExitUpAnim;
    
        //mEnterUpAnim,mOutDown分别构成向下翻页的进出动画
        private Rotate3dAnimation mEnterUpAnim;
        private Rotate3dAnimation mExitDownAnim;
    
        public RollingView(Context context) {
            this(context, null);
        }
    
        public RollingView(Context context, AttributeSet attrs) {
            super(context, attrs);
            // 从xml中获取属性
            TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.RollingView);
            mTextSize = array.getDimension(R.styleable.RollingView_textSize, mTextSize);
            mTextColor = array.getColor(R.styleable.RollingView_textColor, mTextColor);
            array.recycle();
            // 创建默认显示隐藏动画
            createEnterAnimation();
            createExitAnimation();
            // 初始化画笔
            mPaint = new TextPaint();
            // 初始化Handler对象
            mHandler = new Handler(Looper.getMainLooper());
    
            mEnterDownAnim = createAnim(-90, 0, true, true);
            mExitUpAnim = createAnim(0, 90, false, true);
            mEnterUpAnim = createAnim(90, 0, true, false);
            mExitDownAnim = createAnim(0, -90, false, false);
        }
    
        private Rotate3dAnimation createAnim(float start, float end, boolean turnIn, boolean turnUp) {
            final Rotate3dAnimation rotation = new Rotate3dAnimation(start, end, turnIn, turnUp);
            rotation.setDuration(300);
            rotation.setFillAfter(false);
            rotation.setInterpolator(new AccelerateInterpolator());
            return rotation;
        }
    
        /**
         * 设置分页大小
         *
         * @param pageSize
         */
        public void setPageSize(int pageSize) {
            this.mPageSize = this.mUpLimited = pageSize;
        }
    
        /**
         * 设置延迟时间
         *
         * @param millionSeconds
         */
        public void setDelayedDuration(long millionSeconds) {
            this.mDuration = millionSeconds;
        }
    
        /**
         * 设置显示动画
         *
         * @param animation
         */
        public void setEnterAnimation(AnimationSet animation) {
            mEnterAnimSet = animation;
        }
    
        /**
         * 设置隐藏动画
         *
         * @param animation
         */
        public void setExitAnimation(AnimationSet animation) {
            mExitAnimSet = animation;
        }
    
        /**
         * 设置行距
         *
         * @param padding
         */
        public void setTextPadding(int padding) {
            this.mTextPadding = padding;
        }
    
        /**
         * 设置点击后字体颜色
         *
         * @param color
         */
        public void setClickColor(int color) {
            this.mClickColor = color;
        }
    
        /**
         * 设置左图片
         *
         * @param drawable
         */
        public void setLeftDrawable(int drawable) {
            this.mLeftDrawable = drawable;
        }
    
        /**
         * 设置点击事件
         *
         * @param clickListener
         */
        public void setOnItemClickListener(onItemClickListener clickListener) {
            if (null == clickListener) return;
            this.mClickListener = clickListener;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            // 如果是未指定大小,那么设置宽为300px
            int exceptWidth = 300;
            int exceptHeight = 0;
            // 计算高度,如果将高度设置为textSize会很丑,因为文字有默认的上下边距。
            if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY) {
                if (mTextSize > 0) {
                    mPaint.setTextSize(mTextSize);
                    Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
                    exceptHeight = (int) (fontMetrics.bottom - fontMetrics.top);
                }
            }
            int width = resolveSize(exceptWidth, widthMeasureSpec);
            int height = resolveSize(exceptHeight, heightMeasureSpec);
            setMeasuredDimension(width, height);
        }
    
        public void setRollingText(List<String> array) {
            if (null == array || array.isEmpty()) return;
            this.removeAllViews();
            if (mRollingPages == null) {
                mRollingPages = new ArrayList<>();
            }
            mRollingPages.clear();
            // 计算商数
            int quotient = array.size() / mPageSize;
            // 计算余数
            int remainder = array.size() % mPageSize;
            // 计算需要创建多少页
            mPageCount = remainder == 0 ? quotient : quotient + 1;
            for (int i = 0; i < mPageCount; i++) {
                // 创建一个布局
                LinearLayout container = createContainer();
                if (i == mPageCount - 1) {
                    mUpLimited = remainder == 0 ? mPageSize : remainder;
                }
                for (int n = 0; n < mUpLimited; n++) {
                    TextView textView = createTextView(array.get(mPageSize * i + n));
                    container.addView(textView);
                }
                // 添加到分页中
                mRollingPages.add(container);
                this.addView(container);
            }
            // 初始化显示第一页
            mCurrentPage = 0;
            mRollingPages.get(mCurrentPage).setVisibility(VISIBLE);
            this.setVisibility(mRollingPages.get(mCurrentPage));
        }
    
        /**
         * 创建页对象
         *
         * @return
         */
        private LinearLayout createContainer() {
            if (mFrameParams == null) {
                mFrameParams = new LayoutParams(MATCH_PARENT, WRAP_CONTENT);
                mFrameParams.gravity = Gravity.CENTER_VERTICAL;
            }
            LinearLayout container = new LinearLayout(getContext());
            container.setLayoutParams(mFrameParams);
            container.setOrientation(LinearLayout.VERTICAL);
            return container;
        }
    
        private void setVisibility(LinearLayout container) {
            int count = container.getChildCount();
            for (int i = 0; i < count; i++) {
                container.getChildAt(i).setVisibility(VISIBLE);
            }
        }
    
        /**
         * 创建页内容对象
         *
         * @param text
         * @return
         */
        private TextView createTextView(String text) {
            if (mLinearParams == null) {
                mLinearParams = new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
                mLinearParams.gravity = Gravity.CENTER_VERTICAL;
            }
            TextView textView = new TextView(getContext());
            textView.setLayoutParams(mLinearParams);
            textView.setSingleLine();
            textView.setPadding(mTextPadding, mTextPadding, mTextPadding, mTextPadding);
            textView.setEllipsize(TextUtils.TruncateAt.END);
            textView.setTextColor(mTextColor);
            textView.setVisibility(INVISIBLE);
            textView.setText(text);
            if (mLeftDrawable > 0) {
                Drawable drawable = getContext().getResources().getDrawable(mLeftDrawable);
                // Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(), mLeftDrawable);
                // Drawable drawable = new BitmapDrawable(getContext().getResources(), bitmap);
                drawable.setBounds(0, 0, 10, 10);
                textView.setCompoundDrawablePadding(10);
                textView.setCompoundDrawables(drawable, null, null, null);
            }
            textView.setOnClickListener(this);
            // 设置字体大小
            if (mTextSize > 0) {
                textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
            }
            return textView;
        }
    
        private void createEnterAnimation() {
            mEnterAnimSet = new AnimationSet(false);
            TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, 0, 0, TranslateAnimation.RELATIVE_TO_PARENT, 1f, TranslateAnimation.RELATIVE_TO_SELF, 0f);
            AlphaAnimation alphaAnimation = new AlphaAnimation(0f, 1f);
            mEnterAnimSet.addAnimation(translateAnimation);
            mEnterAnimSet.addAnimation(alphaAnimation);
            mEnterAnimSet.setDuration(ANIMATION_DURATION);
        }
    
        private void createExitAnimation() {
            mExitAnimSet = new AnimationSet(false);
            TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, 0, 0, TranslateAnimation.RELATIVE_TO_SELF, 0f, TranslateAnimation.RELATIVE_TO_PARENT, -1f);
            AlphaAnimation alphaAnimation = new AlphaAnimation(1f, 0f);
            mExitAnimSet.addAnimation(translateAnimation);
            mExitAnimSet.addAnimation(alphaAnimation);
            mExitAnimSet.setDuration(ANIMATION_DURATION);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int action = event.getAction();
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                    pause();
                    break;
                case MotionEvent.ACTION_MOVE:
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    resume();
                    break;
            }
            return true;
        }
    
        public void resume() {
            // 只有一页时不进行切换
            if (mPageCount <= 1) return;
            if (mRunnable == null) {
                mRunnable = new RollingRunnable();
            } else {
                mHandler.removeCallbacks(mRunnable);
            }
            mHandler.postDelayed(mRunnable, mDuration);
        }
    
        public void pause() {
            if (mRunnable != null) {
                mHandler.removeCallbacks(mRunnable);
            }
        }
    
        @Override
        public void onClick(View v) {
            if (null == mClickListener) return;
            TextView textView = (TextView) v;
            mClickListener.onItemClick(textView);
            textView.setTextColor(mClickColor);
        }
    
        /**
         * 隐藏当前页,显示下一页任务
         */
        public class RollingRunnable implements Runnable {
    
            @Override
            public void run() {
                // 隐藏当前页
                LinearLayout currentView = mRollingPages.get(mCurrentPage);
                currentView.setVisibility(INVISIBLE);
                if (mExitAnimSet != null) {
                    currentView.startAnimation(mExitAnimSet);// mExitUpAnim);
                }
                mCurrentPage++;
                if (mCurrentPage >= mPageCount) {
                    mCurrentPage = 0;
                }
                // 显示下一页
                LinearLayout nextView = mRollingPages.get(mCurrentPage);
                nextView.setVisibility(VISIBLE);
                setVisibility(nextView);
                if (mEnterAnimSet != null) {
                    nextView.startAnimation(mEnterAnimSet);// mEnterDownAnim);
                }
                mHandler.postDelayed(this, mDuration);
            }
        }
    
        public class Rotate3dAnimation extends Animation {
            private final float mFromDegrees;
            private final float mToDegrees;
            private final boolean mTurnIn;
            private final boolean mTurnUp;
            private float mCenterX;
            private float mCenterY;
            private Camera mCamera;
    
            public Rotate3dAnimation(float fromDegrees, float toDegrees, boolean turnIn, boolean turnUp) {
                mFromDegrees = fromDegrees;
                mToDegrees = toDegrees;
                mTurnIn = turnIn;
                mTurnUp = turnUp;
            }
    
            @Override
            public void initialize(int width, int height, int parentWidth, int parentHeight) {
                super.initialize(width, height, parentWidth, parentHeight);
                mCamera = new Camera();
                mCenterY = getHeight() / 2;
                mCenterX = getWidth() / 2;
            }
    
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                final float fromDegrees = mFromDegrees;
                float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
    
                final float centerX = mCenterX;
                final float centerY = mCenterY;
                final Camera camera = mCamera;
                final int derection = mTurnUp ? 1 : -1;
    
                final Matrix matrix = t.getMatrix();
    
                camera.save();
                if (mTurnIn) {
                    camera.translate(0.0f, derection * mCenterY * (interpolatedTime - 1.0f), 0.0f);
                } else {
                    camera.translate(0.0f, derection * mCenterY * (interpolatedTime), 0.0f);
                }
                camera.rotateX(degrees);
                camera.getMatrix(matrix);
                camera.restore();
    
                matrix.preTranslate(-centerX, -centerY);
                matrix.postTranslate(centerX, centerY);
            }
        }
    
        public interface onItemClickListener {
            void onItemClick(TextView v);
        }
    }

    使用

    // 初始化号外列表
    List<String> haowaiArray = new ArrayList<>();
    haowaiArray.add("[母婴天地] 买尿不湿送婴儿手口湿巾");
    haowaiArray.add("[利民商店] 满100免费配送");
    haowaiArray.add("[果之家] 泰国金枕榴莲8元/kg");
    haowaiArray.add("[户外运动] 户外运动专业装备搜集");
    haowaiArray.add("[天天特价] 只要9.9还包邮");
    haowaiArray.add("[尖端潮品] 折叠电动车");
    haowaiArray.add("[黑科技] 智能VR带你装13");
    haowaiArray.add("[旅行必备] 太阳能充电宝-永不断电");
    // 绑定数据
    mRollingView.setPageSize(4);
    mRollingView.setClickColor(0xff888888);
    mRollingView.setLeftDrawable(R.drawable.drawable_red_dot);
    mRollingView.setRollingText(haowaiArray);
    mRollingView.setOnItemClickListener(this);
    
    ...
    
    @Override
    public void onItemClick(TextView v) {
        // handle item click event
    }
    
    @Override
    public void onResume() {
        super.onResume();
        mRollingView.resume();
    }
    @Override
    public void onPause() {
        super.onPause();
        mRollingView.pause();
    }

  • 相关阅读:
    OO第三单元总结
    oo第二单元总结
    oo第一单元总结
    OO助教工作总结
    当QSY遇上XL尺码的小黄衫
    终点亦是起点
    敏捷开发规范化
    Beta阶段性总结
    需求存在,功能存在——Alpha阶段性总结
    Gitlab Burndown Chart
  • 原文地址:https://www.cnblogs.com/magics/p/6654850.html
Copyright © 2011-2022 走看看