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; } }
- Textview文字闪烁效果(Runnable和Timer两种实现方法)
- 两种方法实现文字阴影效果
- 实现文字闪烁效果
- Handler实现TextView文字闪烁
- android中TextView的文字实现动态效果,走马灯效果,闪烁效果
- android中TextView的文字实现动态效果,走马灯效果,闪烁效果
- android中TextView的文字实现动态效果,走马灯效果,闪烁效果
- Android自定义TextView闪烁文字的效果
- TextView跑马灯效果的两种实现方法
- 实现Thread类的两种方法(继承和实现runnable接口)
- 一个TextView实现文字两种颜色
- LinearGradient和Matrix实现动态的文字闪烁效果
- Android 文字自动滚动(跑马灯)效果的两种实现方法
- Android 文字自动滚动(跑马灯)效果的两种实现方法
- Android 文字自动滚动(跑马灯)效果的两种实现方法
- Android 文字自动滚动(跑马灯)效果的两种实现方法
- Android 文字自动滚动(跑马灯)效果的两种实现方法
- Android 文字自动滚动(跑马灯)效果的两种实现方法[特别好使]
- java解析PDF文件,并获取到指定数据.Eg
- HBase原理-数据读取流程解析
- Webmagic爬虫--②爬自己的CSDN博客列表
- CentOS(Red Hat内核)MongoDB3.4企业版安装
- qt-udp协议编程
- Textview文字闪烁效果(Runnable和Timer两种实现方法)
- 人工智能的三个层次
- Integer等包装类判断相等
- Android的异步消息处理机制---Handler机制总结
- cow2转raw
- iOS OpenGL ES2.0 开发实例 (转载)
- Python 面向对象 编程(一)
- 电子凭证 : Java 生成 Pdf
- Android Studio 连接 MySQL 云端数据库