• Android 公告新闻消息资讯之垂直滚动效果


    垂直滚动新闻栏的实现原理:

      就是一个自定义的LinearLayout,并且textView能够循环垂直滚动,而且条目可以点击,显示区域最多显示2个条目,并且还有交替的属性垂直移动的动画效果,通过线程来控制滚动的实现。

    、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

    自定义属性:

     <style name="AppTheme" parent="@android:style/Theme.Light.NoTitleBar">
            <item name="android:windowNoTitle">true</item>
        </style>

        <declare-styleable name="NoticeView">
            <attr name="gap" format="integer" />
            <attr name="animDuration" format="integer" />
        </declare-styleable>

    、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

    自定义控件的获取属性方法都一样:

       //获取自定义属性
            TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.NoticeView);
            mAdverHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, jdAdverHeight, getResources().getDisplayMetrics());
            int gap = array.getInteger(R.styleable.NoticeView_gap, mGap);
            //关闭清空TypedArray,防止内存泄露
            int animDuration = array.getInteger(R.styleable.NoticeView_animDuration, mAnimDuration);
            //关闭清空TypedArray
            array.recycle();

    、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

    自定义条目布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:background="@drawable/blue_line_bg4"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:gravity="center_vertical"
        android:layout_marginBottom="10dp"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/tag"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:background="@drawable/blue_line_bg"
            android:padding="5dp"
            android:text="最新"
            android:textColor="#ff0000" />

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:ellipsize="end"
            android:singleLine="true"
            android:text="价格惊呆!电信千兆光纤上市"
            android:textColor="#000000"
            android:textSize="12sp" >
        </TextView>

    </LinearLayout>

    ...........................................................................................................................

    //适配器

    package com.notice.scroll;

    import java.util.List;

    import android.view.LayoutInflater;
    import android.view.View;
    import android.widget.TextView;
    import android.widget.Toast;

    public class NoticeAdapter {
        private List<NoticeEntity> mDatas;

        public NoticeAdapter(List<NoticeEntity> datas) {
            this.mDatas = datas;
            if (datas == null || datas.isEmpty()) {
                throw new RuntimeException("nothing to show");
            }
        }

        /**
         * 获取数据的条数
         *
         * @return
         */
        public int getCount() {
            return mDatas == null ? 0 : mDatas.size();
        }

        /**
         * 获取摸个数据
         *
         * @param position
         * @return
         */
        public NoticeEntity getItem(int position) {
            return mDatas.get(position);
        }

        /**
         * 获取条目布局
         *
         * @param parent
         * @return
         */
        public View getView(NoticeView parent) {
            return LayoutInflater.from(parent.getContext()).inflate(R.layout.item, null);
        }

        /**
         * 条目数据适配
         *
         * @param view
         * @param data
         */
        public void setItem(final View view, final NoticeEntity data) {
            TextView tv = (TextView) view.findViewById(R.id.title);
            tv.setText(data.title);
            TextView tag = (TextView) view.findViewById(R.id.tag);
            tag.setText(data.url);
            // 你可以增加点击事件
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // 比如打开url
                    Toast.makeText(view.getContext(), data.url, Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

    、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

    公告实体

    package com.notice.scroll;

    public class NoticeEntity {
        public String title;
        public String url;
        public NoticeEntity(String title, String url) {
            super();
            this.title = title;
            this.url = url;
        }
    }

    、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

    自定义View

    package com.notice.scroll;
    public class NoticeView extends LinearLayout {
        //控件高度
        private float mAdverHeight = 0f;
        //间隔时间
        private final int mGap = 4000;
        //动画间隔时间
        private final int mAnimDuration = 1000;
        //显示文字的尺寸
        private final float TEXTSIZE = 20f;
        private NoticeAdapter mAdapter;
        private final float jdAdverHeight = 50;
        //显示的view
        private View mFirstView;
        private View mSecondView;
        //播放的下标
        private int mPosition;
        //线程的标识
        private boolean isStarted;
        //画笔
        private Paint mPaint;
     
        public NoticeView(Context context) {
            this(context, null);
        }
     
        public NoticeView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
     
        public NoticeView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context, attrs, defStyleAttr);
        }
     
        /**
         * 初始化属性
         * @param context
         * @param attrs
         * @param defStyleAttr
         */
        private void init(Context context, AttributeSet attrs, int defStyleAttr) {
            //设置为垂直方向
            setOrientation(VERTICAL);
            //抗锯齿效果
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            //获取自定义属性
            TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.NoticeView);
            mAdverHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, jdAdverHeight, getResources().getDisplayMetrics());
            int gap = array.getInteger(R.styleable.NoticeView_gap, mGap);
            //关闭清空TypedArray,防止内存泄露
            int animDuration = array.getInteger(R.styleable.NoticeView_animDuration, mAnimDuration);
     
            if (mGap <= mAnimDuration) {
                gap = mGap;
                animDuration = mAnimDuration;
            }
            //关闭清空TypedArray
            array.recycle();
        }
     
        /**
         * 设置数据
         */
        public void setAdapter(NoticeAdapter adapter) {
            this.mAdapter = adapter;
            setupAdapter();
        }
     
        /**
         * 开启线程
         */
        public void start() {
     
            if (!isStarted && mAdapter.getCount() > 1) {
                isStarted = true;
                postDelayed(mRunnable, mGap);//间隔mgap刷新一次UI
            }
        }
     
        /**
         * 暂停滚动
         */
        public void stop() {
            //移除handle更新
            removeCallbacks(mRunnable);
            //暂停线程
            isStarted = false;
        }
        /**
         * 设置数据适配
         */
        private void setupAdapter() {
            //移除所有view
            removeAllViews();
            //只有一条数据,不滚东
            if (mAdapter.getCount() == 1) {
                mFirstView = mAdapter.getView(this);
                mAdapter.setItem(mFirstView, mAdapter.getItem(0));
                addView(mFirstView);
            } else {
                //多个数据
                mFirstView = mAdapter.getView(this);
                mSecondView = mAdapter.getView(this);
                mAdapter.setItem(mFirstView, mAdapter.getItem(0));
                mAdapter.setItem(mSecondView, mAdapter.getItem(1));
                //把2个添加到此控件里
                addView(mFirstView);
                addView(mSecondView);
                mPosition = 1;
                isStarted = false;
            }
        }
        /**
         * 测量控件的宽高
         *
         * @param widthMeasureSpec
         * @param heightMeasureSpec
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            if (LayoutParams.WRAP_CONTENT == getLayoutParams().height) {
                getLayoutParams().height = (int) mAdverHeight;
            } else {
                mAdverHeight = getHeight();
            }
     
            if (mFirstView != null) {
                mFirstView.getLayoutParams().height = (int) mAdverHeight;
            }
            if (mSecondView != null) {
                mSecondView.getLayoutParams().height = (int) mAdverHeight;
            }
        }
     
        /**
         * 画布局
         *
         * @param canvas
         */
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            mPaint.setColor(Color.WHITE);
    mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, TEXTSIZE, getResources().getDisplayMetrics()));
            mPaint.setStyle(Paint.Style.STROKE);
            canvas.drawText("恭喜你中了5000w大奖", TEXTSIZE, getHeight() * 2 / 3, mPaint);//写文字2/3的高度
        }
        /**
         * 垂直滚蛋
         */
        private void performSwitch() {
            //属性动画控制控件滚动,y轴方向移动
            ObjectAnimator animator1 = ObjectAnimator.ofFloat(mFirstView, "translationY", mFirstView.getTranslationY() - mAdverHeight);
            ObjectAnimator animator2 = ObjectAnimator.ofFloat(mSecondView, "translationY", mSecondView.getTranslationY() - mAdverHeight);
            //动画集
            AnimatorSet set = new AnimatorSet();
            set.playTogether(animator1, animator2);//2个动画一起
            set.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {//动画结束
                    mFirstView.setTranslationY(0);
                    mSecondView.setTranslationY(0);
                    View removedView = getChildAt(0);//获得第一个子布局
                    mPosition++;
                    //设置显示的布局
                    mAdapter.setItem(removedView, mAdapter.getItem(mPosition % mAdapter.getCount()));
                    //移除前一个view
                    removeView(removedView);
                    //添加下一个view
                    addView(removedView, 1);
                }
            });
            set.setDuration(mAnimDuration);//持续时间
            set.start();//开启动画
        }
        private AnimRunnable mRunnable = new AnimRunnable();
        private class AnimRunnable implements Runnable {
            @Override
            public void run() {
                performSwitch();
                postDelayed(this, mGap);
            }
        }
     
        /**
         * 销毁View的时候调用
         */
        @Override
        protected void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            //停止滚动
            stop();
        }
        /**
         * 屏幕 旋转
         *
         * @param newConfig
         */
        @Override
        protected void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
        }
    }

    ......................................................................................................

    启动Activity

    package com.notice.scroll;

    public class ScrollNoticeActivity extends Activity {
        private List<NoticeEntity> mDataList = new ArrayList<NoticeEntity>();
        private TextView mNoticeTextView;
        private NoticeAdapter mNoticeAdapter;
        private NoticeView mNoticeView;
        private Handler mHandler = new Handler() {
            public void handleMessage(android.os.Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                case 1:
                    int index = msg.arg1 + 1;
                    if (index >= mDataList.size()) {
                        index = 0;
                    }
                    mNoticeTextView.setText(mDataList.get(index).title);
                    mHandler.sendMessageDelayed(mHandler.obtainMessage(1, index, 0), 2000);
                    break;

                default:
                    break;
                }
            };
        };

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initData();

        }

        private void initData() {
            mDataList.add(new NoticeEntity("剩余流量查询XXXXXXXX", "最新"));
            mDataList.add(new NoticeEntity("恭喜你中了5000w大奖!", "最火爆"));
            mDataList.add(new NoticeEntity("新入网用户领取福利专区", "HOT"));
            mDataList.add(new NoticeEntity("温馨提示此乃诈骗消息", "new"));
            mNoticeTextView = (TextView) findViewById(R.id.tv_notice);
            mNoticeAdapter = new NoticeAdapter(mDataList);
            mNoticeView = (NoticeView) findViewById(R.id.tv_notices);
            mNoticeView.setAdapter(mNoticeAdapter);
            // 开启线程滚动
            mNoticeView.start();
            getNotices();
        }

        /**
         * 直接通过设置textview达到公告显示的效果
         */
        private void getNotices() {
            if (mDataList.size() > 0) {
                mNoticeTextView.setText(mDataList.get(0).title);
                mHandler.sendMessageDelayed(mHandler.obtainMessage(1, 0, 0), 2000);
            }
        }
    }

  • 相关阅读:
    背包九讲
    最小生成树 prime + 队列优化
    最小生成树 prime poj1287
    树状数组--转载
    O(n)求1-n的逆元
    数据结构--线段树
    博弈
    RMQ 数据结构
    BZOJ3687 计算子集和的异或和
    Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined)D Dense Subsequence
  • 原文地址:https://www.cnblogs.com/itcqx/p/5345881.html
Copyright © 2020-2023  润新知