当前位置: 移动技术网 > 移动技术>移动开发>Android > Android自定义View实现仿1号店垂直滚动广告条代码

Android自定义View实现仿1号店垂直滚动广告条代码

2019年07月24日  | 移动技术网移动技术  | 我要评论

效果图展示,图片有点卡,耐心看会,原程序是很流畅的

实现步骤:

  • 声明变量
  • 初始化画笔、文本大小和坐标
  • onmeasure()适配wrap_content的宽高
  • ondraw()画出根据坐标画出两段text
  • 监听点击事件
  • 在activity中实现点击事件

实现原理(坐标变换原理):整个过程都是基于坐标y的增加和交换进行处理的,y值都会一直增加到endy,然后进行交换逻辑

步骤一:声明变量

由于1号店是两句话的滚动,所以我们也是使用两句话来实现的

private paint mpaint;
private float x, starty, endy, firsty, nextstarty, secondy;
//整个view的宽高是以第一个为标准的,所以第二句话长度必须小于第一句话
private string[] text = {"今日特卖:毛衣3.3折>>>", "公告:全场半价>>>"};
private float textwidth, textheight;
//滚动速度
private float speech = 0;
private static final int change_speech = 0x01;
//是否已经在滚动
private boolean isscroll = false;

步骤二:初始化画笔、文本大小和坐标

以第一句话为标准来做控件的宽高标准

//初始化画笔
mpaint = new paint();
mpaint.setcolor(color.red);
mpaint.settextsize(30);
//测量文字的宽高,以第一句话为标准
rect rect = new rect();
mpaint.gettextbounds(text[0], 0, text[0].length(), rect);
textwidth = rect.width();
textheight = rect.height();
//文字开始的x,y坐标
//由于文字是以基准线为基线的,文字底部会突出一点,所以向上收5px
x = getx() + getpaddingleft();
starty = gettop() + textheight + getpaddingtop() - 5;
//文字结束的x,y坐标
endy = starty + textheight + getpaddingbottom();
//下一个文字滚动开始的y坐标
//由于文字是以基准线为基线的,文字底部会突出一点,所以向上收5px
nextstarty = gettop() - 5;
//记录开始的坐标
firsty = starty;
secondy = nextstarty;

步骤三:onmeasure()适配wrap_content的宽高

如果学习过自定义view的话,下面的代码应该很熟悉,就是适配warp_content的模板代码:

@override
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
 super.onmeasure(widthmeasurespec, heightmeasurespec);
 int width = measurewidth(widthmeasurespec);
 int height = measureheight(heightmeasurespec);
 setmeasureddimension(width, height);
}
private int measureheight(int heightmeasurespec) {
 int result = 0;
 int size = measurespec.getsize(heightmeasurespec);
 int mode = measurespec.getmode(heightmeasurespec);
 if (mode == measurespec.exactly) {
  result = size;
 } else {
  result = (int) (getpaddingtop() + getpaddingbottom() + textheight);
  if (mode == measurespec.at_most) {
   result = math.min(result, size);
  }
 }
 return result;
}
private int measurewidth(int widthmeasurespec) {
 int result = 0;
 int size = measurespec.getsize(widthmeasurespec);
 int mode = measurespec.getmode(widthmeasurespec);
 if (mode == measurespec.exactly) {
  result = size;
 } else {
  result = (int) (getpaddingleft() + getpaddingright() + textwidth);
  if (mode == measurespec.at_most) {
   result = math.min(result, size);
  }
 }
 return result;
}

步骤四:ondraw()画出根据坐标画出两段text(已修复:text停下来时闪一下的bug)

通过handler来改变速度

通过isscroll锁,来控制handler只改变一次

通过invalidate一直重绘两句话的文字

@override
protected void ondraw(canvas canvas) {
 super.ondraw(canvas);
 //启动滚动
 if (!isscroll) {
  mhandler.sendemptymessagedelayed(change_speech, 2000);
  isscroll = true;
 }
 canvas.drawtext(text[0], x, starty, mpaint);
 canvas.drawtext(text[1], x, nextstarty, mpaint);
 starty += speech;
 nextstarty += speech;
 //超出view的控件时
 if (starty > endy || nextstarty > endy) {
  if (starty > endy) {
   //第一次滚动过后交换值
   starty = secondy;
   nextstarty = firsty;
  } else if (nextstarty > endy) {
   //第二次滚动过后交换值
   starty = firsty;
   nextstarty = secondy;
  }
  speech = 0;
  isscroll = false;
 }
 invalidate();
}

private handler mhandler = new handler() {
 @override
 public void handlemessage(message msg) {
  super.handlemessage(msg);
  switch (msg.what) {
   case change_speech:
    speech = 1f;
    break;
  }
 }
};

步骤五:监听点击事件(已修复:点击事件错乱的问题)

在自定义view重写dispatchtouchevent处理点击事件,这个也是模板代码:

public ontouchlistener listener;
public interface ontouchlistener {
 void touchlistener(string s);
}
public void setlistener(ontouchlistener listener) {
 this.listener = listener;
}
@override
public boolean dispatchtouchevent(motionevent event) {
 switch (event.getaction()) {
  case motionevent.action_down:
  case motionevent.action_move:
   //点击事件
   if (listener != null) {
    if (starty >= firsty && nextstarty < firsty) {
     listener.touchlistener(text[0]);
    } else if (nextstarty >= firsty && starty < firsty) {
     listener.touchlistener(text[1]);
    }
   }
   break;
 }
 return true;
}

步骤六:在activity中实现点击事件

public class vertextviewactivity extends appcompatactivity {
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_ver_text_view);
  vertextview tv_ver = (vertextview) findviewbyid(r.id.tv_ver);
  tv_ver.setlistener(new vertextview.ontouchlistener() {
   @override
   public void touchlistener(string s) {
    toast.maketext(vertextviewactivity.this, s, toast.length_long).show();
   }
  });
 }
}

布局文件

<?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="horizontal">
 <imageview
  android:layout_width="120dp"
  android:layout_height="30dp"
  android:background="@drawable/vertextview" />
 <com.handsome.app3.custom.vertextview.vertextview
  android:id="@+id/tv_ver"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:background="#ffffff"
  android:padding="8dp" />
</linearlayout>

整个类的源码:

/**
 * =====作者=====
 * 许英俊
 * =====时间=====
 * 2016/10/11.
 */
public class vertextview extends view {
 private paint mpaint;
 private float x, starty, endy, firsty, nextstarty, secondy;
 //整个view的宽高是以第一个为标准的,所以第二句话长度必须小于第一句话
 private string[] text = {"今日特卖:毛衣3.3折>>>", "公告:全场半价>>>"};
 private float textwidth, textheight;
 //滚动速度
 private float speech = 0;
 private static final int change_speech = 0x01;
 //是否已经在滚动
 private boolean isscroll = false;
 private handler mhandler = new handler() {
  @override
  public void handlemessage(message msg) {
   super.handlemessage(msg);
   switch (msg.what) {
    case change_speech:
     speech = 1f;
     break;
   }
  }
 };
 public vertextview(context context, attributeset attrs) {
  super(context, attrs);
  //初始化画笔
  mpaint = new paint();
  mpaint.setcolor(color.red);
  mpaint.settextsize(30);
  //测量文字的宽高,以第一句话为标准
  rect rect = new rect();
  mpaint.gettextbounds(text[0], 0, text[0].length(), rect);
  textwidth = rect.width();
  textheight = rect.height();
  //文字开始的x,y坐标
  //由于文字是以基准线为基线的,文字底部会突出一点,所以向上收5px
  x = getx() + getpaddingleft();
  starty = gettop() + textheight + getpaddingtop() - 5;
  //文字结束的x,y坐标
  endy = starty + textheight + getpaddingbottom();
  //下一个文字滚动开始的y坐标
  //由于文字是以基准线为基线的,文字底部会突出一点,所以向上收5px
  nextstarty = gettop() - 5;
  //记录开始的坐标
  firsty = starty;
  secondy = nextstarty;
 }
 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
  super.onmeasure(widthmeasurespec, heightmeasurespec);
  int width = measurewidth(widthmeasurespec);
  int height = measureheight(heightmeasurespec);
  setmeasureddimension(width, height);
 }
 private int measureheight(int heightmeasurespec) {
  int result = 0;
  int size = measurespec.getsize(heightmeasurespec);
  int mode = measurespec.getmode(heightmeasurespec);
  if (mode == measurespec.exactly) {
   result = size;
  } else {
   result = (int) (getpaddingtop() + getpaddingbottom() + textheight);
   if (mode == measurespec.at_most) {
    result = math.min(result, size);
   }
  }
  return result;
 }
 private int measurewidth(int widthmeasurespec) {
  int result = 0;
  int size = measurespec.getsize(widthmeasurespec);
  int mode = measurespec.getmode(widthmeasurespec);
  if (mode == measurespec.exactly) {
   result = size;
  } else {
   result = (int) (getpaddingleft() + getpaddingright() + textwidth);
   if (mode == measurespec.at_most) {
    result = math.min(result, size);
   }
  }
  return result;
 }
 @override
 protected void ondraw(canvas canvas) {
  super.ondraw(canvas);
  //启动滚动
  if (!isscroll) {
   mhandler.sendemptymessagedelayed(change_speech, 2000);
   isscroll = true;
  }
  canvas.drawtext(text[0], x, starty, mpaint);
  canvas.drawtext(text[1], x, nextstarty, mpaint);
  starty += speech;
  nextstarty += speech;
  //超出view的控件时
  if (starty > endy || nextstarty > endy) {
   if (starty > endy) {
    //第一次滚动过后交换值
    starty = secondy;
    nextstarty = firsty;
   } else if (nextstarty > endy) {
    //第二次滚动过后交换值
    starty = firsty;
    nextstarty = secondy;
   }
   speech = 0;
   isscroll = false;
  }
  invalidate();
 }
 public ontouchlistener listener;
 public interface ontouchlistener {
  void touchlistener(string s);
 }
 public void setlistener(ontouchlistener listener) {
  this.listener = listener;
 }
 @override
 public boolean dispatchtouchevent(motionevent event) {
  switch (event.getaction()) {
   case motionevent.action_down:
   case motionevent.action_move:
    //点击事件
    if (listener != null) {
     if (starty >= firsty && nextstarty < firsty) {
      listener.touchlistener(text[0]);
     } else if (nextstarty >= firsty && starty < firsty) {
      listener.touchlistener(text[1]);
     }
    }
    break;
  }
  return true;
 }
}

以上所述是小编给大家介绍的android自定义view实现仿1号店垂直滚动广告条代码,希望对大家有所帮助

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网