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

  就是一个自定义的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);
        }
    }
}

Android 公告新闻消息资讯之垂直滚动效果的更多相关文章

  1. Android 仿 新闻阅读器 菜单弹出效果(附源码DEMO)

    这一系列博文都是:(android高仿系列)今日头条 --新闻阅读器 (一) 开发中碰到问题之后实现的,觉得可能有的开发者用的到或则希望独立成一个小功能DEMO,所以就放出来这么一个DEMO. 原本觉 ...

  2. DIV垂直滚动效果源码

    <div id="demo" style="width: 300; overflow: hidden; line-height:24px; height: 100p ...

  3. js实现的新闻列表垂直滚动实现详解

    js实现的新闻列表垂直滚动实现详解:新闻列表垂直滚动效果在大量的网站都有应用,有点自然是不言而喻的,首先由于网页的空间有限,使用滚动代码可以使用最小的空间提供更多的信息量,还有让网页有了动态的效果,更 ...

  4. Expression Blend4经验分享:文字公告无缝循环滚动效果

    这次分享一个类似新闻公告板的无缝循环滚动效果,相信很多项目都会应用到这个效果.之前我也百度了一下,网上的一些Silverlight的文字或图片滚动效果,都是一次性滚动的,如果要做到无缝循环滚动,多数要 ...

  5. [转]jquery.vTicker(垂直滚动)

    转至:http://www.w3ci.com/plugin/660.html 简介 vTicker 是一款非常小巧的 jQuery 垂直滚动插件,压缩后只有 2KB.vTicker 支持自定义滚动时间 ...

  6. Android TextView多行垂直滚动

    在Android应用中,有时候需要TextView可以垂直滚动,今天我就介绍一下怎么实现的.在布局里: <TextView android:id="@+id/tvCWJ" a ...

  7. Android自定义垂直滚动自动选择日期控件

    ------------------本博客如未明正声明转载,皆为原创,转载请注明出处!------------------ 项目中需要一个日期选择控件,该日期选择控件是垂直滚动,停止滚动时需要校正日期 ...

  8. android开源新闻小程序、3D翻转公告效果、小说检索、Kotlin开发TODO清单等源码

    Android精选源码 开源新闻小程序源码分享 android动态壁纸.锁屏动画.来电秀等源码 android笔记App效果源码 Android实现3D版翻页公告效果 android小说搜索阅读源码 ...

  9. TextSwitcher实现文本自动垂直滚动

    实现功能:用TextSwitcher实现文本自动垂直滚动,类似淘宝首页广告条. 实现效果: 注意:由于网上横向滚动的例子比较多,所以这里通过垂直的例子演示. 实现步骤:1.extends TextSw ...

随机推荐

  1. 小米手机收到升级鸿蒙OS提示?官方回应

    虽然尚未得到官方确认,但华为“鸿蒙”OS已经成为网络热门话题,在机圈引发热议. 本周,互联网上出现了显示为MIUI 10手机被锁定,屏幕上出现“小米将于2020年9月15日全面停止服务,届时您所有设备 ...

  2. css选择器权重、样式继承、默认样式

    学过css的小伙伴都是指css选择器的权重 !important Infinity 行间样式 1000 id   100 class|属性|伪类 10 标签|伪元素 1 通配符 0 权重相同 相同cs ...

  3. Power Tower

    题目大意:给出一段长为 \(n\) 的序列 \(a_1,a_2,\cdots,a_n\) ,一个模数 \(m\) .每次询问给定 \(l,r\) 求 \(a_l^{{a_{l+1}^\cdots}^{ ...

  4. git仓库管理

    删除本地仓库当前关联的无效远程地址,再为本地仓库添加新的远程仓库地址 git remote -v //查看git对应的远程仓库地址 git remote rm origin //删除关联对应的远程仓库 ...

  5. 深入理解class

    一, class和自定义类型的区别: 1,类声明不会被提升. 2,类声明的代码自动运行在严格模式. 3,类的所有方法都是不可枚举的,而自定的方法必须使用Object.defineProperty来设置 ...

  6. 当DIV内出现滚动条,fixed实效怎么办?

    sticky    盒位置根据正常流计算(这称为正常流动中的位置),然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位.在所有情况下( ...

  7. 使用Redis SortedSet实现增量更新

    导读:前段时间有个需求是提供一个接口供客户端增量更新数据,当有数据被删除了以后客户端也需要感知到,并且要支持一定并发: 关键词:高并发,增量更新 前言 何谓增量更新,顾名思义就是只更新变化的部分,这样 ...

  8. list的泛型

    更新记录 [1]2020.02.12-21:26 1.完善内容 正文 在学习list集合时,我看到书上写list的格式时 List<E> list = new ArrayList<& ...

  9. swift中利用系统线程实现异步加载数据同步更新UI

    swift中的使用案例样式 // Mark: -数据源更新 typealias AddDataBlock = () ->Void var updataBlock:AddDataBlock? fu ...

  10. qt 程序发布打包

    1. 首先把 release 版本的 exe 复制到其他文件夹,比如 Desktop\test 2. 使用开始菜单中 qt 里面的控制台窗口,使用 cd 命令打开到 Desktop\test 位置,然 ...