Textview文字闪烁效果(Runnable和Timer两种实现方法)

来源:互联网 发布:距离矢量路由选择算法 编辑:程序博客网 时间:2024/05/20 04:27

这个demo我写在了listView上,如果有需要单独使用(不在listView中使用),请自行抽取

特别说明:我这里用了Runnable和Timer两种实现方法,我最后在项目中使用的是Timer。因为Timer更好。我下面会详细给出理由和测试。感兴趣的可以看看。不想深究的,请直接看后面的Timer实现方法

写在前面:虽然最后Timer可以实现在listview中展示Textview文字的闪烁,但是还是有问题的。如:有的条目不需要展示,就算GONE掉了,但是Timer还是会走到。我试过各种方法,都没解决。一旦单纯的解决GONE调后Timer还执行的问题,就会出现其他的伴随问题。唉。。。
不过,虽然有这样的问题,但是不影响使用。我用实际项目做过测试,我们项目的动态列表中的数据类型比较多,还是比较复杂的。我每条都加上这个闪烁的Textview,每页请求数据10条,我在手机上开了多个应用,然后滑动加载数据滑动了近50页,没有任何崩溃、反应卡顿的现象。

需求:listView中,给每个条目上的文字都加上文字闪烁效果

一个控件有规律的做一个展示动作,首先我们能想到的是,handler周期性的发消息,接收然后处理。但是这里因为一些需求原因,展示效果限制到了listView上。这个时候,让每个条目都发handler去处理,显然是不明智的。可以自定义一下Textview,让它自身具备让文字显示周期变化的效果

第一种方法:Runnable
自定义Textview,让它自身就有变化文字颜色的功能
FlickerTextView

package com.demo.mydemo;import android.content.Context;import android.graphics.Canvas;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.widget.TextView;public class FlickerTextView extends TextView implements Runnable {    private boolean flag = false;    public FlickerTextView(Context context) {        this(context, null);    }    public FlickerTextView(Context context, @Nullable AttributeSet attrs) {        this(context, attrs, -1);    }    public FlickerTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        flag = false;    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        if (flag) {            setTextColor(0xffff3038);        } else {            setTextColor(0xffff7214);        }    }    @Override    public void run() {        while (true) {            synchronized (this) {                try {                    flag = !flag;                    postInvalidate();                    // 每执行一次暂停40毫秒                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }}

然后,就是布局文件了
activity_main

<?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="match_parent"    android:orientation="vertical"    >    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:orientation="horizontal">        <TextView            android:id="@+id/tv_1"            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:background="#5500ff00"            android:gravity="center"            android:paddingBottom="5dp"            android:paddingTop="5dp"            android:text="重新加载"            android:textSize="20sp"/>        <TextView            android:id="@+id/tv_2"            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:background="#550000ff"            android:gravity="center"            android:paddingBottom="5dp"            android:paddingTop="5dp"            android:text="加载更多"            android:textSize="20sp"/>    </LinearLayout>    <ListView        android:id="@+id/listview"        android:layout_width="match_parent"        android:layout_height="match_parent"/></LinearLayout>

item

<?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="match_parent"    android:orientation="vertical"    >    <com.demo.mydemo.FlickerTextView        android:id="@+id/tv"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:gravity="center"        android:paddingBottom="5dp"        android:paddingTop="5dp"        /></LinearLayout>

最后,是在Activity中使用
MainActivity

package com.demo.mydemo;import android.app.Activity;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ListView;import android.widget.TextView;import java.util.ArrayList;public class MainActivity extends Activity {    private TextView tv_1;    private TextView tv_2;    private ListView listview;    private ArrayList<String> dataList;    private MyAdapter myAdapter;    private int index = 0;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        tv_1 = findViewById(R.id.tv_1);        tv_2 = findViewById(R.id.tv_2);        listview = findViewById(R.id.listview);        dataList = new ArrayList();        myAdapter = new MyAdapter();        listview.setAdapter(myAdapter);        setData(0);        tv_1.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                setData(0);            }        });        tv_2.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                index++;                setData(index);            }        });    }    private void setData(int index) {        if (index == 0) {            dataList.clear();        }        for (int i = 1 + index * 10; i < 11 + index * 10; i++) {            dataList.add("==第" + i + "条==");        }        myAdapter.notifyDataSetChanged();    }    class MyAdapter extends BaseAdapter {        @Override        public int getCount() {            return dataList.size();        }        @Override        public Object getItem(int position) {            return dataList.get(position);        }        @Override        public long getItemId(int position) {            return position;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            ViewHolder holder;            if (convertView == null) {                convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, null);                holder = new ViewHolder();                holder.tv = convertView.findViewById(R.id.tv);                //new Thread(holder.tv).start();                convertView.setTag(holder);            } else {                holder = (ViewHolder) convertView.getTag();            }            holder.tv.setText(dataList.get(position));            new Thread(holder.tv).start();            return convertView;        }        private class ViewHolder {            private FlickerTextView tv;        }    }}

功能说明:
点击tv_1(重新加载),会清空之前的数据,重新填充1-10,这10条数据,模拟listView的下拉刷新
点击tv_2(加载更多),会在现有数据基础上再增加10条数据,模拟listView的上拉加载更多

特别注意:
特别注意:
特别注意:

1、请注意MyAdapter 下getView方法中的new Thread(holder.tv).start()这句话,
如果它写在convertView复用设置以外。即:

    if (convertView == null) {        ......        convertView.setTag(holder);    } else {        holder = (ViewHolder) convertView.getTag();    }    new Thread(holder.tv).start();

意外着每个item,都会创建一个子线程,去跑这个item的Textview的文字颜色变化。这个时候,多次点击“加载更多”,当listView中的数据很多的时候,滑动,项目会崩溃,错误日志是:

java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Out of memory

,这个很好理解,因为item很多,而每个item都会去创建一个子线程,只有item数据足够多,内存溢出是肯定的。

2、现在,对上面的OOM异常进行一下优化,getView中的代码变成了:

        @Override        public View getView(int position, View convertView, ViewGroup parent) {            ViewHolder holder;            if (convertView == null) {                convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, null);                holder = new ViewHolder();                holder.tv = convertView.findViewById(R.id.tv);                new Thread(holder.tv).start();                convertView.setTag(holder);            } else {                holder = (ViewHolder) convertView.getTag();            }            holder.tv.setText(dataList.get(position));            //new Thread(holder.tv).start();            return convertView;        }

注意new Thread(holder.tv).start()这句话的位置,变到了convertView 复用那里去了。

这个时候,运行起来程序,随便“加载更多”点多少次,这么滑动,都不会OOM了。

问题解决了。

这个时候,我改一下需求,item中,只有position是10的倍数的时候,才让文字变动,或者有点击事件,或者才让这个FlickerTextView展示出来(毕竟,实际中,也不太可能每个item都展示闪烁文字,应该是满足条件的才展示)。

怎么办?这个文字闪烁,是在convertView 复用那里的,在那里做判断,因为涉及复用,很容易出问题。但是如果把new Thread(holder.tv).start()放到外面,数据多了又会OOM。

为了解决这个问题,现在,用Timer来实现

FlickerTextView2

package com.demo.mydemo;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.util.Log;import android.widget.TextView;import java.util.Timer;import java.util.TimerTask;public class FlickerTextView2 extends TextView {    private boolean flag = false;    public FlickerTextView2(Context context) {        this(context, null);    }    public FlickerTextView2(Context context, @Nullable AttributeSet attrs) {        this(context, attrs, -1);    }    public FlickerTextView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        flag = false;        init();    }    private void init() {        Log.e("init","init");        Timer timer = new Timer();        TimerTask taskcc = new TimerTask() {            public void run() {                Log.e("Timer","Timer");                flag = !flag;                postInvalidate();            }        };        // 参数分别是delay(多长时间后执行),duration(执行间隔)        timer.schedule(taskcc, 1000, 1000);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        Log.e("onDraw","onDraw");        if (flag) {            setTextColor(0xff000000);        } else {            setTextColor(0xffff0000);        }    }}

其他用法,同上Activity代码。仅仅改一下Adapter就行

    class MyAdapter extends BaseAdapter {        @Override        public int getCount() {            return dataList.size();        }        @Override        public Object getItem(int position) {            return dataList.get(position);        }        @Override        public long getItemId(int position) {            return position;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            ViewHolder holder;            if (convertView == null) {                convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, null);                holder = new ViewHolder();                holder.tv = convertView.findViewById(R.id.tv);                //                new Thread(holder.tv).start();                convertView.setTag(holder);            } else {                holder = (ViewHolder) convertView.getTag();            }            holder.tv.setText(dataList.get(position));            //            new Thread(holder.tv).start();            if (position % 10 == 0) {                holder.tv.setOnClickListener(new View.OnClickListener() {                    @Override                    public void onClick(View v) {                        Toast.makeText(MainActivity.this, "哈哈", Toast.LENGTH_SHORT).show();                    }                });            }else{                holder.tv.setOnClickListener(null);            }            return convertView;        }        private class ViewHolder {            private FlickerTextView2 tv;        }    }
阅读全文
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 月经来了一个月了还不停怎么办 对办公室的异性老师产生好感怎么办 上古卷轴5任务NPC老打我怎么办 1岁半宝宝走路内八字怎么办 最近几个月例假周期都25天怎么办 从pr导出的视频大小不一样怎么办 合作医疗收据丢了不给报销怎么办 沧州新生医院—老人腹胀了该怎么办 内痔疮术后一个月吃了点辣椒怎么办 肛周脓肿手术后大便干怎么办 月经半个月了还没干净怎么办 房东出租违建房不退房租怎么办 上海公租房住满5年后怎么办 监狱对死缓犯人延长转为无期怎么办 手机号码办理的宽带不想要了怎么办 朋友诈骗罪被关看守所了该怎么办 打架被拘留家里有孩子没人看怎么办 刑事拘留满37天给逮捕了怎么办 因打架被拘留十五天释放后会怎么办 犯罪人在拘留所生了小孩怎么办 我申请了进京证更换车辆怎么办 丈夫去世前想把财产留给妻子怎么办 假货中通代收货款发现是假货怎么办 注册志愿者时身份证被使用该怎么办 双眼皮贴贴的皮肤送了怎么办? 满60岁社保末满十五年怎么办 眼角膜少了一块怎么办应该吃什么 左右胸相差一个罩杯左右怎么办 穿一字肩的裙子没有无肩内衣怎么办 农业网柑橘被奄24小时怎么办 钱包被偷了小偷抓到了钱不认怎么办 快高考了很想学却没有动力怎么办? 孩子高三了学习状态不好怎么办 离婚时对方说把钱都花了怎么办 挂科太多学校不给毕业证怎么办 大专挂科太多学校让延期毕业怎么办 安卓手机老是收到垃圾短信怎么办 高铁站行李拉安检仪上应该怎么办 连壁金融立案了投资钱怎么办 联壁金融倒了投资人的钱怎么办 改签的高铁票错过了怎么办