1. 背景
需要做一個跑馬燈效果的文字展示,本方案更適用于開發機頂盒應用的同學們,
2. 需求
2.1 展示書籍的頁面,文字過多的時候需要折疊
2.2 當焦點在此書籍上的時候,需要將折疊的文字滾動起來
3. 需求剖析
3.1 正常情況下使用跑馬燈,只需要設定Textview的以下屬性即可
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
設定完成之后,當這個TextView有焦點的時候,且文字過長的時候,就會展現跑馬燈效果,注意當TextView請求焦點的時候,跑馬燈效果才展示,否則無效,
3.2 但是在機頂盒上,app是需要使用焦點效果來展示你所選的當前item,也就是通常所說的“落焦”,
3.3 這時候使用跑馬燈的時候會產生兩個問題
問題一:我的item是在一個recycleView當中,充當跑馬燈的TextView只是recycleView中子view 中的子view,我外層的布局需要拿到焦點,才能在recycleView中正常移動,
問題二:即使我將TextView設定請求焦點,那么當我從當前的item向上滑動的時候,recycleView就不再認為我是在他的子view間移動,recycleView的翻頁效果會有問題,就是當你上一行展示了一半,但是我焦點已經在上一行了,但是上一行卻沒有展示完全,如下圖所示:

4. 解決思路
4.1 我需要有一個不需要焦點,仍然能夠展現跑馬燈的控制元件,避免與recycleView之間的沖突
4.2 同時我這個控制元件也需要有TextView原有的功能,便于我在簡單情況下使用跑馬燈效果
5. 代碼
5.1 布局檔案 resource_item.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/dimen_166dp"
android:layout_height="@dimen/dimen_234dp">
<ImageView
android:id="@+id/item_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/column_test_image" />
<plat.skytv.main.view.MarqueeText
android:id="@+id/item_name"
android:layout_width="match_parent"
android:layout_height="@dimen/dimen_37dp"
android:alpha="0.6"
android:singleLine="true"
android:background="@android:color/black"
android:gravity="center"
android:layout_gravity="bottom"
android:textColor="@color/colorWhite"
android:textSize="@dimen/dimen_17sp" />
<ImageView
android:id="@+id/item_cornerMask"
style="@style/bigConerMask" />
<ImageView
android:id="@+id/item_focus"
style="@style/FocusStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/column_grid_item_selector" />
</FrameLayout>
5.2 自定義view
package plat.skytv.main.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.TextPaint;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatTextView;
import plat.skytv.main.util.PLog;
public class MarqueeText extends AppCompatTextView implements Runnable {
private int xLocation;// 當前滾動的位置
private boolean isStop = false;
private int textWidth;
private boolean isMeasure = false;
private float speed = 1; // 移動速度
private String string; // 需要繪制得文字
public MarqueeText(Context context) {
super(context);
}
public MarqueeText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MarqueeText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
float textHeight;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isMeasure) {// 文字寬度只需獲取一次就可以了
getTextWidth();
textHeight = getTextHeight(getPaint());
isMeasure = true;
string = this.getText().toString();
}
canvas.drawText(string, xLocation, getHeight() / 2 + textHeight / 2, getPaint());
}
/**
* http://blog.csdn.net/u014702653/article/details/51985821
* 詳細解說了
*
* @param
* @return
*/
private float getTextHeight(Paint paint) {
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
return Math.abs((fontMetrics.bottom - fontMetrics.top)) / 2;
}
/**
* 獲取文字寬度
*/
private void getTextWidth() {
Paint paint = this.getPaint();
string = this.getText().toString();
PLog.e("getTextWidth str = " + string);
textWidth = (int) paint.measureText(string);
}
@Override
public void run() {
xLocation -= speed;// 滾動速度
if (isStop) { // 停止滾動后恢復初始狀態
xLocation = 0;
return;
}
if (textWidth <= (-xLocation)) {
//也就是說文字已經到頭了
xLocation = getWidth();
}
postInvalidate();
postDelayed(this, 10);
}
// 開始滾動 針對不能請求焦點的情況
public void startScroll() {
if (textWidth <= this.getWidth()) { // 文字長度 <= view長度,不需要滾動
return;
}
setText("");// 需要設定空 否則展示兩個文字
setSingleLine(false); // 需要設定false,否則無法滾動
isStop = false;
this.removeCallbacks(this);
post(this);
}
// 停止滾動
public void stopScroll() {
isStop = true;
setText(string);
setSingleLine(true);
}
}
5.3 使用
在recycleView系結資料的時候設定焦點變化監聽
ImageView mItemFocus = itemView.findViewById(R.id.item_focus); // 展示焦點效果的view
MarqueeText mItemName = itemView.findViewById(R.id.item_name);
mItemFocus.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
mItemName.startScroll();
} else {
mItemName.stopScroll();
}
}
});
6. 問題
6.1 在布局檔案中,設定了singleline = true,結果,呼叫 startScroll 時無法滾動,
6.2 在滾動之前必須將本TextView的text設定為空串,否則將出現兩個文本,
6.3 先存疑,以后找到結果了再貼上去
7. 參考檔案:
7.1 http://blog.csdn.net/u014702653/article/details/51985821
7.2 https://www.cnblogs.com/hyhy904/p/11329139.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/263480.html
標籤:其他
下一篇:安卓第一趴
