Android – Demo(一) TextView 自定义走马灯效果(横向,纵向)
效果图:
-
布局:
<!--横向滚动--> <com.example.toollibs.OverWriteClass.MarqueeHorizontal android:id="@+id/marqueeH" android:layout_width="match_parent" android:layout_height="60dp"/> <!--纵向滚动--> <com.example.toollibs.OverWriteClass.MarqueeVertical android:id="@+id/marqueeV" android:layout_width="match_parent" android:layout_height="60dp" android:layout_marginTop="@dimen/margin_10"/>
-
调用:
horizontal = findViewById(R.id.marqueeH); vertical = findViewById(R.id.marqueeV); private void setVertical() { //字体大小设置 vertical.setTextSize(20); //字体颜色设置 vertical.setTextColor(Color.YELLOW); //背景颜色设置 vertical.setBackgroundColor(Color.BLACK); //换行间隔 vertical.setDelay(5000);//5s //显示内容 vertical.setContents(DEFAULT_TEXT); } private void setHorizontal() { horizontal.setTextSize(20); horizontal.setTextColor(Color.YELLOW); horizontal.setBackgroundColor(Color.BLACK); //滚动速度 horizontal.setSpeed(5); horizontal.setContents(DEFAULT_TEXT2); }
-
控件代码:
//横向滚动效果 代码:
a) MarqueeHorizontal.java:
public class MarqueeHorizontal extends View implements Runnable { private final String TAG = "MARQUEE_HORIZONTAL"; private Paint paint; private int viewWidth; private int viewHeight; private Rect rect;//用于获取文字宽度 //字体属性 private float textSize = 20.0f; private int textColor = Color.YELLOW; private int speed = 1; private float textWidth; private String contents; private int backgroundColor = Color.BLACK; private Thread thread; public MarqueeHorizontal(Context context) { this(context, null); } public MarqueeHorizontal(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public MarqueeHorizontal(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); } private void init(AttributeSet attrs) { //解析自定义属性...未加 rect = new Rect(); //初始化画笔 paint = new Paint(); paint.setAntiAlias(true); paint.setColor(textColor); paint.setTextSize(sp2px(textSize)); } private void startRoll() { thread = new Thread(this); thread.start(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { viewWidth = getWidth(); viewHeight = getHeight(); // adjustText();//当文本过短,调整 但重绘时感觉有点穿帮 startRoll(); super.onLayout(changed, left, top, right, bottom); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(backgroundColor); Paint.FontMetricsInt metricsInt = paint.getFontMetricsInt(); float centerY = (viewHeight - metricsInt.top - metricsInt.bottom) / 2.0f; canvas.drawText(contents, viewWidth, centerY, paint); } private void adjustText() { textWidth = getTextWidth(contents); if(textWidth < viewWidth){ String blank = getBlanks(contents.length()); int times = (int) (viewWidth / textWidth) + 1; String newCont = ""; if(times%2==0){ for(int i=0; i<times/2; i++){ newCont += (contents + blank); } }else{ for(int i=0; i<times/2; i++){ newCont += (contents + blank); } newCont += contents; } contents = newCont; } Log.i(TAG, "conts: " + contents); } private String getBlanks(int length) { String temp = "\u3000"; StringBuilder builder = new StringBuilder(); for(int i=0; i<length; i++){ builder.append(temp); } return builder.toString(); } private float getTextWidth(String str){ if (str == null || str == "") { return 0; } if (rect == null) { rect = new Rect(); } paint.getTextBounds(str, 0, str.length(), rect); return rect.width(); } @Override public void run() { while (!TextUtils.isEmpty(contents)) { if(getScrollX()>viewWidth+getTextWidth(contents)){ scrollTo(0,0); } try { Thread.sleep(20); scrollBy(speed, 0); postInvalidate(); } catch (InterruptedException e) { e.printStackTrace(); } } } public void setContents(String contents) { this.contents = contents; } public void setTextSize(float textSize) { this.textSize = sp2px(textSize); paint.setTextSize(sp2px(textSize)); } public void setTextColor(int textColor) { this.textColor = textColor; paint.setColor(textColor); } public void setSpeed(int speed) { this.speed = speed; } @Override public void setBackgroundColor(int backgroundColor) { this.backgroundColor = backgroundColor; } private int sp2px(float spValue) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, getResources().getDisplayMetrics()); } }
//纵向滚动效果代码(英文效果待优化:分割行时与中文有差别)
b) MarqueeVertical.java
public class MarqueeVertical extends View implements Runnable{ private final String TAG = "MARQUEE_VERTICAL"; private Paint paint; private int viewWidth; private int viewHeight; //字体属性 private float textSize = 20.0f; private int textColor = Color.YELLOW; private String contents; private List<String> list = new ArrayList<>(); private int backgroundColor = Color.BLACK;//默认背景色 private int rows;//文本分割后总行数 private int numInRow;//每行最多容纳字数 private int padValue = 15;//左右两边缩进距离 piex private int offset=0;//记录画布滚动距离 private int delay = 3000;//滚动间隔 private Thread thread;//控制自动滚动 private OverScroller scroller;//使滚动效果跟平滑 public MarqueeVertical(Context context) { this(context, null); } public MarqueeVertical(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public MarqueeVertical(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } private void init(Context context, AttributeSet attrs) { //解析自定义属性...未加 //初始化画笔 paint = new Paint(); paint.setAntiAlias(true); paint.setColor(textColor); paint.setTextSize(sp2px(textSize));// scroller = new OverScroller(context); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { viewWidth = getWidth(); viewHeight = getHeight(); Log.i(TAG, "w&h: " + viewWidth + ", " +viewHeight); calculateRows(); parseContent(); startRoll(); super.onLayout(changed, left, top, right, bottom); } private void calculateRows() { numInRow = (int) ((viewWidth-padValue*2) / textSize); rows = contents.length()%numInRow==0 ? contents.length()/numInRow : contents.length()/numInRow+1; } private void parseContent(){ for(int i=0; i<rows; i++){ String temp = contents.substring(numInRow*i, Math.min(numInRow*(i+1), contents.length())); list.add(temp); Log.i(TAG, "line: " + temp); } } private void startRoll() { thread = new Thread(this); thread.start(); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(backgroundColor); //计算绘制文本中心,然后将其移至控件中心 Paint.FontMetricsInt metricsInt = paint.getFontMetricsInt(); float centerY = (viewHeight - metricsInt.top - metricsInt.bottom) / 2.0f; for(int i=0; i<list.size(); i++){ canvas.drawText(list.get(i), padValue, centerY + viewHeight*i, paint);//每行相隔距离为一个控件高度 } } @Override public void computeScroll() { super.computeScroll(); if(scroller.computeScrollOffset()){ scrollTo(scroller.getCurrX(), scroller.getCurrY()); invalidate(); } } @Override public void run() { if(list.size()>1){ for(;;){ Log.i(TAG, "offset: " + offset); if(offset>=viewHeight*(list.size()-1)){ scrollTo(0,0); offset = -viewHeight; } try { Thread.sleep(delay); scroller.startScroll(0, offset, 0, viewHeight); offset += viewHeight; postInvalidate(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public void setDelay(int delay) { this.delay = delay; } public void setTextSize(float textSize) { this.textSize = sp2px(textSize); paint.setTextSize(sp2px(textSize)); } public void setTextColor(int textColor) { this.textColor = textColor; paint.setColor(textColor); } public void setContents(String contents) { this.contents = contents; } @Override public void setBackgroundColor(int backgroundColor) { this.backgroundColor = backgroundColor; } private int sp2px(float spValue) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, getResources().getDisplayMetrics()); } }