<declare-styleable name="ADTextView">
<!--文字进入与消失的时间-->
<attr name="ad_text_view_speed" format="integer"/>
<!--文字停留在中心的时间-->
<attr name="ad_text_view_interval" format="integer"/>
<!--前缀文字颜色-->
<attr name="ad_text_front_color" format="color"/>
<!--前缀文字大小-->
<attr name="ad_text_front_size" format="dimension"/>
<!--内容文字颜色-->
<attr name="ad_text_content_color" format="color"/>
<!--内容文字大小-->
<attr name="ad_text_content_size" format="dimension"/>
</declare-styleable>
<!--文字进入与消失的时间-->
<attr name="ad_text_view_speed" format="integer"/>
<!--文字停留在中心的时间-->
<attr name="ad_text_view_interval" format="integer"/>
<!--前缀文字颜色-->
<attr name="ad_text_front_color" format="color"/>
<!--前缀文字大小-->
<attr name="ad_text_front_size" format="dimension"/>
<!--内容文字颜色-->
<attr name="ad_text_content_color" format="color"/>
<!--内容文字大小-->
<attr name="ad_text_content_size" format="dimension"/>
</declare-styleable>
效果图:
实现仿京东垂直滚动广告栏,它是一个动态的无限自动轮播图,让我们看看它是怎么实现的:
先看一看布局文件:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.bawei.com.wangruixin20171116.MainActivity"> <com.bawei.com.wangruixin20171116.ADTextView android:id="@+id/re" android:layout_width="match_parent" android:layout_height="20dp" /> </RelativeLayout>
MainActivity
package com.bawei.com.wangruixin20171116; import android.graphics.Color; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { private ADTextView mADTextView1; private ArrayList<ADEnity> mList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } public void init(){ mADTextView1 = (ADTextView) findViewById(R.id.re); mList = new ArrayList<>(); mList.add(new ADEnity("推荐","国货PK美国货,结果让人震惊", "连接1")); mList.add(new ADEnity("推荐","这次XiPhone,可能让你迷路", "连接2")); mList.add(new ADEnity("HOT", "为什么吉普,奥巴马都爱钓鱼", "连接3")); mList.add(new ADEnity("HOT", "虽然我字难看,但我钢笔好看啊", "连接4")); mADTextView1.setSpeed(3); mADTextView1.setInterval(1500); mADTextView1.setFrontColor(Color.RED); mADTextView1.setBackColor(Color.BLACK); mADTextView1.setmTexts(mList); // mADTextView.setOnItemClickListener(new ADTextView.OnItemClickListener() { // @Override // public void onClick(String mUrl) { // if (mToast == null) { // mToast = Toast.makeText(getActivity(), mUrl, Toast.LENGTH_LONG); // } else { // mToast.setText(mUrl); // } // mToast.show(); // } // }); } }ADEnity
package com.bawei.com.wangruixin20171116; /** * */ public class ADEnity { private String mFront ; //前面的文字 private String mBack ; //后面的文字 private String mUrl ;//包含的链接 public ADEnity(String mFront, String mBack,String mUrl) { this.mFront = mFront; this.mBack = mBack; this.mUrl = mUrl; } public String getmUrl() { return mUrl; } public void setmUrl(String mUrl) { this.mUrl = mUrl; } public String getmFront() { return mFront; } public void setmFront(String mFront) { this.mFront = mFront; } public String getmBack() { return mBack; } public void setmBack(String mBack) { this.mBack = mBack; } }ADTextView
package com.bawei.com.wangruixin20171116; /** * Created by Zhouyf on 2017/11/14. */ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import java.util.List; import java.util.Timer; import java.util.TimerTask; /** * 仿京东垂直滚动广告栏 * */ public class ADTextView extends View { private int mSpeed; //文字出现或消失的速度 建议1~5 private int mInterval; //文字停留在中间的时长 private int mFrontColor; //前缀颜色 private int mContentColor; //内容的颜色 private int mFrontTextSize; //前缀文字大小 private int mContentTextSize; //内容文字大小 private List<ADEnity> mTexts; //显示文字的数据源 private int mY = 0; //文字的Y坐标 private int mIndex = 0; //当前的数据下标 private Paint mPaintContent; //绘制内容的画笔 private Paint mPaintFront; //绘制前缀的画笔 private boolean isMove = true; //文字是否移动 private String TAG = "ADTextView"; private boolean hasInit = false; private boolean isPaused = false; public interface onClickListener { public void onClick(String mUrl); } private onClickListener onClickListener; public void setOnClickListener(onClickListener onClickListener) { this.onClickListener = onClickListener; } public ADTextView(Context context) { this(context, null); } public ADTextView(Context context, AttributeSet attrs) { super(context, attrs); obtainStyledAttrs(attrs); init(); } //获取资源文件 private void obtainStyledAttrs(AttributeSet attrs) { TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.ADTextView); mSpeed = array.getInt(R.styleable.ADTextView_ad_text_view_speed, 1); mInterval = array.getInt(R.styleable.ADTextView_ad_text_view_interval, 2000); mFrontColor = array.getColor(R.styleable.ADTextView_ad_text_front_color, Color.RED); mContentColor = array.getColor(R.styleable.ADTextView_ad_text_content_color, Color.BLACK); mFrontTextSize = (int) array.getDimension(R.styleable.ADTextView_ad_text_front_size, SizeUtil.Sp2Px(getContext(), 15)); mContentTextSize = (int) array.getDimension(R.styleable.ADTextView_ad_text_content_size, SizeUtil.Sp2Px(getContext(), 15)); array.recycle(); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: if (onClickListener != null) { onClickListener.onClick(mTexts.get(mIndex).getmUrl()); } break; } return true; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(DensityUtil.dip2px(getContext(), 500), DensityUtil.dip2px(getContext(), 40)); } //测量宽度 private int measureHeight(int heightMeasureSpec) { int result = 0; int mode = MeasureSpec.getMode(heightMeasureSpec); int size = MeasureSpec.getSize(heightMeasureSpec); if (mode == MeasureSpec.EXACTLY) { result = size; } else { //高度至少为两倍字高 int mfronTextHeight = (int) (mPaintFront.descent() - mPaintFront.ascent()); //前缀文字字高 int mContentTextHeight = (int) (mPaintContent.descent() - mPaintContent.ascent()); //内容文字字高 result = Math.max(mfronTextHeight, mContentTextHeight) * 2; if (mode == MeasureSpec.AT_MOST) { result = Math.min(result, size); } } return result; } //测量高度 private int measureWidth(int widthMeasureSpec) { int result = 0; int mode = MeasureSpec.getMode(widthMeasureSpec); int size = MeasureSpec.getSize(widthMeasureSpec); if (mode == MeasureSpec.EXACTLY) { result = size; } else { //宽度最小十个字的宽度 String text = "十个字十个字十个字字"; Rect rect = new Rect(); mPaintContent.getTextBounds(text, 0, text.length(), rect); result = rect.right - rect.left; if (mode == MeasureSpec.AT_MOST) { result = Math.min(result, size); } } return result; } //设置数据源 public void setmTexts(List<ADEnity> mTexts) { this.mTexts = mTexts; } //设置广告文字的停顿时间 public void setInterval(int mInterval) { this.mInterval = mInterval; } //设置速度 public void setSpeed(int spedd) { this.mSpeed = spedd; } //设置前缀的文字颜色 public void setFrontColor(int mFrontColor) { mPaintFront.setColor(mFrontColor); } //设置正文内容的颜色 public void setBackColor(int mBackColor) { mPaintContent.setColor(mBackColor); } //初始化默认值 private void init() { mIndex = 0; mPaintFront = new Paint(); mPaintFront.setAntiAlias(true); mPaintFront.setDither(true); mPaintFront.setTextSize(mFrontTextSize); mPaintFront.setColor(mFrontColor); mPaintContent = new Paint(); mPaintContent.setAntiAlias(true); mPaintContent.setDither(true); mPaintContent.setTextSize(mContentTextSize); mPaintContent.setColor(mContentColor); } @Override protected void onDraw(Canvas canvas) { if (mTexts != null) { ADEnity model = mTexts.get(mIndex); String font = model.getmFront(); String back = model.getmBack(); //绘制前缀 Rect indexBound = new Rect(); mPaintFront.getTextBounds(font, 0, font.length(), indexBound); //绘制内容文字 Rect contentBound = new Rect(); mPaintContent.getTextBounds(back, 0, back.length(), contentBound); if (mY == 0 && hasInit == false) { mY = getMeasuredHeight() - indexBound.top; hasInit = true; } //移动到最上面 if (mY <= 0 - indexBound.bottom) { Log.i(TAG, "onDraw: " + getMeasuredHeight()); mY = getMeasuredHeight() - indexBound.top; mIndex++; isPaused = false; } canvas.drawText(back, 0, back.length(), (indexBound.right - indexBound.left) + 20, mY, mPaintContent); canvas.drawText(font, 0, font.length(), 10, mY, mPaintFront); //移动到中间 if (!isPaused && mY <= getMeasuredHeight() / 2 - (indexBound.top + indexBound.bottom) / 2) { isMove = false; isPaused = true; Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { postInvalidate(); isMove = true; } }, mInterval); } mY -= mSpeed; //循环使用数据 if (mIndex == mTexts.size()) { mIndex = 0; } //如果是处于移动状态时的,则延迟绘制 //计算公式为一个比例,一个时间间隔移动组件高度,则多少毫秒来移动1像素 if (isMove) { postInvalidateDelayed(2); } } } }DensityUtil
package com.bawei.com.wangruixin20171116; import android.content.Context; public class DensityUtil { /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 根据手机的分辨率从 px(像素) 的单位 转成为 dp */ public static int px2dip(Context context, float pxValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); } }SizeUtil
package com.bawei.com.wangruixin20171116; import android.content.Context; import android.util.TypedValue; /** * */ public class SizeUtil { public static int Dp2Px(Context context, int dpi) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpi, context.getResources().getDisplayMetrics()); } public static int Px2Dp(Context context, int px) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px, context.getResources().getDisplayMetrics()); } public static int Sp2Px(Context context, int sp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics()); } public static int Px2Sp(Context context, int px) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, px, context.getResources().getDisplayMetrics()); } }