android自动跑马灯,Android-最强跑马灯

Android--最强跑马灯

Android 跑马灯已经有很多版本,从最基本的TextView,到重写TextView使TextView取消焦点限制,还有重写TextView利用ScrollTo方法写的,基本都能满足一般需要。然而在使用过程中,发现一些意外---有时会不播放,刷新线程还在继续但就是不播放,最后在github上找到一个用动画实现跑马灯的项目(项目地址:https://github.com/ened/Android-MarqueeView,再次对作者表示感谢),改造了一番,总算ok了。以后再也不用为跑马灯烦恼了。

特点:

1. 文字长短都有跑马灯效果。

2. 可以控制速度

代码:

package com.example.test_marquee;

import android.content.Context;

import android.graphics.Paint;

import android.text.Editable;

import android.text.TextWatcher;

import android.util.AttributeSet;

import android.util.Log;

import android.view.Gravity;

import android.view.View;

import android.view.ViewGroup;

import android.view.animation.Animation;

import android.view.animation.Interpolator;

import android.view.animation.LinearInterpolator;

import android.view.animation.TranslateAnimation;

import android.widget.LinearLayout;

import android.widget.ScrollView;

import android.widget.TextView;

/**

* LinearLayout作为父View,必须有一个子TextView

*

* 利用动画实现

*/

public class MarqueeView extends LinearLayout {

private static final int TEXTVIEW_VIRTUAL_WIDTH = 2000;/* TextView默认宽度 */

private static final int DEFAULT_SPEED = 35;/* 默认滚动速度 越大滚动越慢 */

private static final int DEFAULT_ANIMATION_PAUSE = 0;/* 出去动画与进入动画的时间间隔 */

private static final String TAG = MarqueeView.class.getSimpleName();

private TextView mTextField;/* 该跑马灯的孙子View之TextView */

private ScrollView mScrollView;/* 该跑马灯的子View之mScrollView */

private Animation mMoveTextOut = null;/* 作用于TextView的动画 --出去 */

private Animation mMoveTextIn = null;/* 作用于TextView的动画 --进入 */

private Paint mPaint;

private int mSpeed = DEFAULT_SPEED;

private int mAnimationPause = DEFAULT_ANIMATION_PAUSE;

private Interpolator mInterpolator = new LinearInterpolator();

private Runnable mAnimationStartRunnable;

/** 字符串之间的间隔 */

private String interval = " ";

private String stringOfItem = "";

/** str+interval的长度 */

private float widthOfItem = 0;

private float widthOfTextView;

private String stringOfTextView = "";

private float startXOfOut = 0;

private float endXOfOut = 0;

private float startXOfIn = 0;

private float endXOfIn = 0;

public MarqueeView(Context context) {

super(context);

init(context);

}

public MarqueeView(Context context, AttributeSet attrs) {

super(context, attrs);

init(context);

}

public MarqueeView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

init(context);

}

private void init(Context context) {

// init helper

mPaint = new Paint();

mPaint.setAntiAlias(true);

mPaint.setStrokeWidth(1);

mPaint.setStrokeCap(Paint.Cap.ROUND);

mInterpolator = new LinearInterpolator();

}

// 当给子View分配位置和尺寸时调用。

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

super.onLayout(changed, l, t, r, b);

Logcat.d(TAG, "onLayout called!" + "changed: " + changed);

if (getChildCount() == 0 || getChildCount() > 1) {

throw new RuntimeException(

"MarqueeView must have exactly one child element.");

}

//

if (changed) {

View v = getChildAt(0);

if (!(v instanceof TextView)) {

throw new RuntimeException(

"The child view of this MarqueeView must be a TextView instance.");

}

initView(getContext());

mTextField.setText(mTextField.getText());

}

}

/** Starts the configured marquee effect. */

public void startMarquee() {

Logcat.d(TAG, "startMarquee called");

startTextFieldAnimation();

}

// 一旦开始动画,动画结束开始由监听器负责。

private void startTextFieldAnimation() {

mAnimationStartRunnable = new Runnable() {

public void run() {

mTextField.startAnimation(mMoveTextOut);

}

};

postDelayed(mAnimationStartRunnable, mAnimationPause);

}

/**

* Disables the animations.

*/

public void reset() {

if (mAnimationStartRunnable == null)

return;

removeCallbacks(mAnimationStartRunnable);

mTextField.clearAnimation();

mMoveTextOut.reset();

mMoveTextIn.reset();

invalidate();

}

private void prepareAnimation() {

// Measure

mPaint.setTextSize(mTextField.getTextSize());

mPaint.setTypeface(mTextField.getTypeface());

float mTextWidth = mPaint.measureText(mTextField.getText().toString());

float width = getMeasuredWidth();

startXOfOut = -(mTextWidth - width) % widthOfItem;

endXOfOut = -mTextWidth + width;

startXOfIn = -(mTextWidth - width) % widthOfItem;

endXOfIn = -mTextWidth + width;

final int duration = ((int) Math.abs(startXOfOut - endXOfOut) * mSpeed);

if (BuildConfig.DEBUG) {

Log.d(TAG, "(int) Math.abs(startXOfOut - endXOfOut) : "

+ (int) Math.abs(startXOfOut - endXOfOut));

Log.d(TAG, "mSpeed : " + mSpeed);

Log.d(TAG, "startXOfOut : " + startXOfOut);

Log.d(TAG, "endXOfOut : " + endXOfOut);

Log.d(TAG, "startXOfIn : " + startXOfIn);

Log.d(TAG, "endXOfIn : " + endXOfIn);

Log.d(TAG, "duration : " + duration);

}

mMoveTextOut = new TranslateAnimation(startXOfOut, endXOfOut, 0, 0);

mMoveTextOut.setDuration(duration);

mMoveTextOut.setInterpolator(mInterpolator);

mMoveTextOut.setFillAfter(true);

mMoveTextIn = new TranslateAnimation(startXOfIn, endXOfIn, 0, 0);

mMoveTextIn.setDuration(duration);

mMoveTextIn.setStartOffset(mAnimationPause);

mMoveTextIn.setInterpolator(mInterpolator);

mMoveTextIn.setFillAfter(true);

mMoveTextOut.setAnimationListener(new Animation.AnimationListener() {

public void onAnimationStart(Animation animation) {

}

public void onAnimationEnd(Animation animation) {

mTextField.startAnimation(mMoveTextIn);

}

public void onAnimationRepeat(Animation animation) {

}

});

mMoveTextIn.setAnimationListener(new Animation.AnimationListener() {

public void onAnimationStart(Animation animation) {

}

public void onAnimationEnd(Animation animation) {

startTextFieldAnimation();

}

public void onAnimationRepeat(Animation animation) {

}

});

}

/** 初始化子View */

private void initView(Context context) {

// Scroll View

LayoutParams sv1lp = new LayoutParams(LayoutParams.MATCH_PARENT,

LayoutParams.WRAP_CONTENT);

sv1lp.gravity = Gravity.CENTER_HORIZONTAL;

mScrollView = new ScrollView(context);

// Scroll View 1 - Text Field

mTextField = (TextView) getChildAt(0);

removeView(mTextField);

mScrollView.addView(mTextField, new ScrollView.LayoutParams(

TEXTVIEW_VIRTUAL_WIDTH, LayoutParams.WRAP_CONTENT));

mTextField.addTextChangedListener(new TextWatcher() {

@Override

public void beforeTextChanged(CharSequence charSequence, int i,

int i2, int i3) {

}

@Override

public void onTextChanged(CharSequence charSequence, int i, int i2,

int i3) {

}

@Override

public void afterTextChanged(Editable editable) {

Logcat.d(TAG, "afterTextChanged called");

// 如果提供的字符串未被加工过,就先加工,否则就开始动画

if (!stringOfTextView.equals(editable.toString())) {

String str = editable.toString();

mPaint.setTextSize(mTextField.getTextSize());

mPaint.setTypeface(mTextField.getTypeface());

stringOfItem = str + interval;

widthOfItem = mPaint.measureText(stringOfItem);

stringOfTextView = stringOfItem;

widthOfTextView = widthOfItem;

while (widthOfTextView <= 2 * getMeasuredWidth()) {

stringOfTextView += stringOfItem;

widthOfTextView = mPaint.measureText(stringOfTextView);

}

Logcat.d(TAG, "string of TextView deal ok!###");

Logcat.d(TAG, "lengthOfll: " + getMeasuredWidth() + "###");

Logcat.d(TAG, "lengthOfTextView: " + widthOfTextView

+ "###");

Logcat.d(TAG, "CONTENT: " + stringOfTextView + "###");

// 设置起始

mTextField.setText(stringOfTextView);

return;

}

reset();

prepareAnimation();

expandTextView();

post(new Runnable() {

@Override

public void run() {

startMarquee();

}

});

}

});

addView(mScrollView, sv1lp);

}

private void expandTextView() {

ViewGroup.LayoutParams lp = mTextField.getLayoutParams();

lp.width = (int) widthOfTextView + 5;

mTextField.setLayoutParams(lp);

}

}

使用:

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:paddingBottom="@dimen/activity_vertical_margin"

android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

tools:context=".MainActivity" >

android:id="@+id/marqueeView"

android:layout_width="match_parent"

android:layout_height="wrap_content" >

android:id="@+id/tv_marquee"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:ellipsize="end"

android:singleLine="true"

android:text="Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do."

android:textSize="20sp"

android:textStyle="bold" />

下载地址:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/281542.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python:软件目录结构规范

为什么要设计好目录结构&#xff1f; “设计项目目录结构”&#xff0c;就和“代码编码风格”一样&#xff0c;属于个人风格问题。对于这种风格上的规范&#xff0c;一直都存在两种态度&#xff1a; 1.一种认为&#xff0c;这种个人风格问题“无关紧要”。理由是能让程序work就…

开启智能生活新时代 河北省智慧社区建设从各个击破

智慧社区作为智慧城市的重要组成部分&#xff0c;是城市智慧落地的触点&#xff0c;是城市管理、政务服务和市场服务的载体。随着智慧城市的推广以及新一代技术的普及&#xff0c;智慧社区的项目必将迎来新一轮的快速发展。2016年智慧社区成为企业业务落地的承载点&#xff0c;…

C# WPF 表格控件的前后台数据交互?

概述GridControl控件使用我们已经进行了实例讲解&#xff0c;这节内容我们列举一个特殊的应用场景&#xff1a;表格中有一列CheckBox&#xff0c;默认都处于勾选状态&#xff0c;当用户通过界面操作后&#xff0c;我们要确保用户至少选择了一项&#xff0c;相当于一次数据验证&…

Java(C#)基础差异-语法

1、long类型 Java long类型&#xff0c;若赋值大于int型的最大值&#xff0c;或小于int型的最小值&#xff0c;则需要在数字后加L或者l&#xff0c;表示该数值为长整数&#xff0c;如long num2147483650L。 举例如下&#xff1a; public static void main(String[] args) {/** …

android防止左向右滑出程序,Android——ViewPager禁止左右滑动的实现

目录1 背景用ViewPagerBottomNavigationView多个Fragment快速搭建的页面切换架构&#xff0c;一个有四个页面&#xff0c;因为测试需要&#xff0c;需要屏蔽掉中间的两个&#xff0c;做法是&#xff1a;设置不可点击选择&#xff1a;xml布局文件中&#xff0c;BottomNavigation…

Yii2 的快速配置 api 服务 yii2-fast-api

yii2-fast-api yii2-fast-api是一个Yii2框架的扩展&#xff0c;用于配置完善Yii2&#xff0c;以实现api的快速开发。 此扩展默认的场景是APP的后端接口开发&#xff0c;因此偏向于实用主义&#xff0c;并未完全采用restfull的标准&#xff0c;方便前端开发处理接口数据以及各种…

.NET6打包部署到Windows Service

1.安装Nuget包安装以下nuget包支持windows service<PackageReference Include"Microsoft.AspNetCore.Hosting.WindowsServices" Version"6.0.10" /> <PackageReference Include"Microsoft.Extensions.Hosting.WindowsServices" Version…

传统家电在智能家居变革的五大优势

而在众多向智能家居领域转型变革的企业中&#xff0c;看似落后的传统家电企业&#xff0c;却占据着一定的优势。 产品优势 传统家电企业在产品上的优势主要体现在企业拥有产品本身的设计、技术、生产、制造和营销渠道&#xff0c;其产品不论是从外观设计、零件制造还是零件组装…

《Apache Kafka实战》读书笔记-调优Kafka集群

《Apache Kafka实战》读书笔记-调优Kafka集群 作者&#xff1a;尹正杰 版权声明&#xff1a;原创作品&#xff0c;谢绝转载&#xff01;否则将追究法律责任。 一.确定调优目标 1>.常见的非功能性要求 一.性能&#xff08;performance&#xff09;最重要的非功能性需求之一。…

android emoji unicode编码表,unicode编码

unicode编码app是一款字符查找客户端应用&#xff0c;通过unicode编码可以方便寻找特定字符&#xff0c;查看字符表情详细的描述&#xff0c;并且利用unicode编码就可以快捷复制任意unicode编码&#xff0c;提高开发效率&#xff0c;非常的实用&#xff0c;快来下载unicode编码…

物联网商机诱人 芯片商大力搭建生态系统

应用需求变化多端的物联网&#xff0c;虽具备庞大的发展潜力及应用商机&#xff0c;但由于市场过于分散&#xff0c;几乎没有杀手应用可言&#xff0c;因此对有意耕耘相关市场的半导体业者而言&#xff0c;如何借力使力&#xff0c;寻找盟友共同搭建出的生态系统&#xff0c;遂…

ASP.NET Core 6框架揭秘实例演示[30]:利用路由开发REST API

借助路由系统提供的请求URL模式与对应终结点之间的映射关系&#xff0c;我们可以将具有相同URL模式的请求分发给与之匹配的终结点进行处理。ASP.NET的路由是通过EndpointRoutingMiddleware和EndpointMiddleware这两个中间件协作完成的&#xff0c;它们在ASP.NET平台上具有举足轻…

数据库(二)tab补全功能,使数据库支持简体中文,日志管理,备份脚本

一、如何在MySQL数据库中使用tab键补全功能 1.修改主配置文件/etc/my.cnf vim /etc/my.cnf [mysql] #no-auto-rehash auto-rehash 2.重启MySQL服务&#xff0c;登录测试 /etc/init.d/mysqld restart mysql -uroot -p (可在数据库中使用tab键&#xff09; 3.&#xff1b;临时支持…

php new self()关键字的用法

今天开框架源码&#xff0c;发现有用到new self()的用法 有点不懂 在网上查了一下&#xff0c;给大家说一下&#xff1a; 在类中 self的用法 和this的用法差不多 &#xff0c; php new self() 一般在类内部使用&#xff0c;作用是对自身类实例化&#xff0c;下面给个实例讲解…

android listview item置顶,ListView的item置顶

ListView的item设置置顶1.activitypublic class TopListViewActivity extends Activity {private static int ON_TOP 1;private static int CANCEL_TOP 0;public static String TOP_STATES "TOP";private ListView mListView;private List sessionList;private Se…

电信运营商x86服务器定制策略

近几年&#xff0c;伴随云计算、大数据、移动互联网、物联网等新技术从概念到实践&#xff0c;业务、用户数据海量式爆发增长&#xff0c;作为承载这些业务发展的服务器行业也面临巨大的机遇和挑战。一方面&#xff0c;需求的爆发式增长大幅提升了市场空间&#xff0c;尤其是大…

企业数字化转型服务+方案

前言&#xff1a;本文的阅读对象是公司老板、或企业高层管理者&#xff01;1【背景介绍】数字经济与实体经济深度融合是助推我国经济高质量发展的重要环节。为加快数字中国建设&#xff0c;中央和地方政府都出台各类政策扶植数字化转型相关项目。马云在接受采访时也提到&#x…

在 MongoDB 上模拟事务操作来实现支付

我们的产品叫「学海密探」&#xff0c;属于在线教育行业&#xff0c;产品需要有支付功能&#xff0c;然而支付最蛋疼是什么&#xff1f;有人会说是支付宝和微信等支付接口的接入开发&#xff01;没错&#xff0c;但支付接口的开发算是比较简单的了&#xff0c;我觉得凡是跟钱有…

Zabbix server is not running

问题描述 Dashbord中提示Zabbix server is not running 分析过程 首先查看zabbix-server的运行状态 systemctl status zabbix-server 确定是否是active(running)状态&#xff0c;如果不是&#xff0c;重启zabbix-server查看log tail -f /var/log/zabbix/zabbix_server.log 导致…

android 把异常写入到文本里,尝试在Android中将文件写入sdcard时发生FileNotFoundException(权限被拒绝)...

从标题中可以看到&#xff0c;我在Android中将文件写入sdcard时遇到问题.我想写入将在sdcard上的公共空间中的文件&#xff0c;以便任何其他应用程序都可以读取它。首先&#xff0c;我检查sdcard是否已安装&#xff1a;Environment.getExternalStorageState();然后&#xff0c;…