当前位置: 移动技术网 > IT编程>移动开发>Android > android仿百度福袋红包界面

android仿百度福袋红包界面

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

村上里沙和金毛,陶兴尧,白雪公主和七个小矮人国语版

马上到双十一,红包来袭,时间又是充裕,抢红包的时候意外发现了百度的福袋界面还不错,想想还要专门写一篇博文来完成其界面。

当然啦,这其实就是解锁界面的进化版本。不过其包含的知识点还是挺多的,写篇博文记录一下看看具体有哪些技术点啦。看

看百度的效果图:

1.编程思路

看看界面,不难发现,其就是一个放入九张图片的容器,绘制其实可以在其上面另创建一个透明view负责绘制线与圆圈。下面我们将介绍一下实现过程。

㈠自定义viewgroup

我们知道,自定义viewgroup一定需要实现其onlayout()方法。该方法是设置子view位置与尺寸的时候调用。还有一个onmeasure()方法,该方法是测量view及其内容来确定view的宽度和高度。

㈡存储其点与圆的位置及绘制参数

当重回界面的时候,是不会保存上一次绘制界面的内容,必须存储以备重绘时候绘制到界面

㈢简单的缩放动画

㈣自定义view实现绘制界面

㈤绘制完成时,清除界面绘制内容,并且保证不连接重复图片

下面我们将完成这些步骤。

2.自定义viewgroup

开始的任务就是将九张图片平均分布到图片的位置,显示在手机界面中。其代码如下:

public class lyjviewgroup extends viewgroup implements lyjgesturedrawline.onanimationcallback{
  /**
   * 每个点区域的宽度
   */
  private int childwidth;
  /***
   * 上下文
   */
  private context context;
  /***
   * 保存图片点的位置
   */
  private list<lyjgesturepoint> list;
  /***
   * 创建view使其在viewgroup之上。
   */
  private lyjgestureview gesturedrawline;
  private int basenum = 5;
  public lyjviewgroup(context context) {
    super(context);
    this.context = context;
    this.list = new arraylist<>();
    displaymetrics metric = new displaymetrics();
    ((activity) context).getwindowmanager().getdefaultdisplay().getmetrics(metric);
    childwidth = metric.widthpixels / 3;   // 屏幕宽度(像素)
    addchild();
    // 初始化一个可以画线的view
    gesturedrawline = new lyjgestureview(context, list);
    gesturedrawline.setanimationcallback(this);
  }
  public void setparentview(viewgroup parent){
    // 得到屏幕的宽度
    displaymetrics metric = new displaymetrics();
    ((activity) context).getwindowmanager().getdefaultdisplay().getmetrics(metric);
    int width = metric.widthpixels;
    layoutparams layoutparams = new layoutparams(width, width);
    this.setlayoutparams(layoutparams);
    gesturedrawline.setlayoutparams(layoutparams);
    parent.addview(this);
    parent.addview(gesturedrawline);
  }
  @override
  protected void onlayout(boolean changed, int l, int t, int r, int b) {
    for (int i = 0; i < getchildcount(); i++) {
      //第几行
      int rowspan = i / 3;
      //第几列
      int column = i % 3;
      android.view.view v = getchildat(i);
      v.layout(column * childwidth + childwidth / basenum, rowspan * childwidth + childwidth / basenum,
          column * childwidth + childwidth - childwidth / basenum, rowspan * childwidth + childwidth - childwidth / basenum);
    }
  }
  @override
  protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
    super.onmeasure(widthmeasurespec, heightmeasurespec);
    // 遍历设置每个子view的大小
    for (int i = 0; i < getchildcount(); i++) {
      view v = getchildat(i);
      v.measure(widthmeasurespec, heightmeasurespec);
    }
  }

  private void addchild() {
    for (int i = 0; i < 9; i++) {
      imageview image = new imageview(context);
      image.setbackgroundresource(r.drawable.marker);
      this.addview(image);
      invalidate();
      // 第几行
      int rowspan = i / 3;
      // 第几列
      int column = i % 3;
      // 定义点的左上角与右下角的坐标
      int leftx = column * childwidth + childwidth / basenum;
      int topy = rowspan * childwidth + childwidth / basenum;
      int rightx = column * childwidth + childwidth - childwidth / basenum;
      int bottomy = rowspan * childwidth + childwidth - childwidth / basenum;
      lyjgesturepoint p = new lyjgesturepoint(leftx, topy, rightx,bottomy,i);
      this.list.add(p);
    }
  }
  
  @override
  public void startanimationimage(int i) {
    animation animation= animationutils.loadanimation(getcontext(), r.anim.gridlayout_child_scale_anim);
    getchildat(i).startanimation(animation);
  }
}



3.自定义点类

顾名思义,就是为了获取点的相关的属性,其中基础属性图片左上角坐标与右下角坐标,计算图片中心位置以便获取图片中心点。状态标记,表示该点是否绘制到图片。下面是其实体类:

public class lyjgesturepoint {
  private point pointlefttop;//左上角坐标
  private point pointrightbottom;//右下角坐标
  private int centerx;//图片中心点x坐标
  private int centery;//图片中心点y坐标
  private int pointstate;//是否点击了该图片

  private int num;

  public int getnum() {
    return num;
  }

  public int getpointstate() {
    return pointstate;
  }

  public void setpointstate(int pointstate) {
    this.pointstate = pointstate;
  }

  public point getpointlefttop() {
    return pointlefttop;
  }

  public point getpointrightbottom() {
    return pointrightbottom;
  }

  public lyjgesturepoint(int left,int top,int right,int bottom,int i){
    this.pointlefttop=new point(left,top);
    this.pointrightbottom=new point(right,bottom);
    this.num=i;
  }

  public int getcenterx() {
    this.centerx=(this.pointlefttop.x+this.pointrightbottom.x)/2;
    return centerx;
  }

  public int getcentery() {
    this.centery=(this.pointlefttop.y+this.pointrightbottom.y)/2;
    return centery;
  }
}

4.自定义圆类

这个类较简单就三个属性而已(圆中心点坐标及半径),代码如下:

public class lyjcirclepoint {
  private int roundx;//圆中心点x坐标
  private int roundy;//圆中心点y坐标
  private int radiu;//圆半径

  public int getradiu() {
    return radiu;
  }

  public int getroundx() {
    return roundx;
  }

  public int getroundy() {
    return roundy;
  }

  public lyjcirclepoint(int roundx,int roundy,int radiu){
    this.roundx=roundx;
    this.roundy=roundy;
    this.radiu=radiu;
  }
}

5.实现自定义绘制类view

代码如下:

public class lyjgestureview extends android.view.view {
  /***
   * 声明直线画笔
   */
  private paint paint;
  /***
   * 声明圆圈画笔
   */
  private paint circlepaint;
  /***
   * 画布
   */
  private canvas canvas;
  /***
   * 位图
   */
  private bitmap bitmap;
  /***
   * 装有各个view坐标的集合,用于判断点是否在其中
   */
  private list<lyjgesturepoint> list;
  /***
   * 记录画过的线
   */
  private list<pair<lyjgesturepoint, lyjgesturepoint>> linelist;
  /***
   * 记录画过的圆
   */
  private list<lyjcirclepoint> circlepoints;
  /**
   * 手指当前在哪个point内
   */
  private lyjgesturepoint currentpoint;
  /***
   * 手指按下动画
   */
  private onanimationcallback animationcallback;
  public interface onanimationcallback{
    public void startanimationimage(int i);
  }

  public void setanimationcallback(onanimationcallback animationcallback) {
    this.animationcallback = animationcallback;
  }

  public lyjgestureview(context context, list<lyjgesturepoint> list){
    super(context);
    log.i(getclass().getname(), "gesturedrawline");
    paint = new paint(paint.dither_flag);// 创建一个画笔
    circlepaint=new paint(paint.dither_flag);
    displaymetrics metric = new displaymetrics();
    ((activity)context).getwindowmanager().getdefaultdisplay().getmetrics(metric);
    log.i(getclass().getname(), "widthpixels" + metric.widthpixels);
    log.i(getclass().getname(), "heightpixels" + metric.heightpixels);
    bitmap = bitmap.createbitmap(metric.widthpixels, metric.heightpixels, bitmap.config.argb_8888); // 设置位图的宽高
    canvas = new canvas();
    canvas.setbitmap(bitmap);
    paint.setstyle(paint.style.stroke);// 设置非填充
    paint.setstrokewidth(20);// 笔宽20像素
    paint.setcolor(color.rgb(245, 142, 33));// 设置默认连线颜色
    paint.setantialias(true);// 不显示锯齿
    circlepaint.setstyle(paint.style.fill);
    circlepaint.setstrokewidth(1);
    circlepaint.setantialias(true);
    circlepaint.setcolor(color.rgb(245, 142, 33));

    this.list = list;
    this.linelist = new arraylist<>();
    this.circlepoints=new arraylist<>();
  }

  @override
  public boolean ontouchevent(motionevent event) {
    switch (event.getaction()){
      case motionevent.action_down:
        // 判断当前点击的位置是处于哪个点之内
        currentpoint = getpointat((int) event.getx(), (int) event.gety());
        if (currentpoint != null) {
          currentpoint.setpointstate(constants.point_state_selected);
          this.animationcallback.startanimationimage(currentpoint.getnum());
          canvas.drawcircle(currentpoint.getcenterx(), currentpoint.getcentery(), 20, circlepaint);
          circlepoints.add(new lyjcirclepoint(currentpoint.getcenterx(),currentpoint.getcentery(),20));
        }
        invalidate();
        break;
      case motionevent.action_move:
        clearscreenanddrawlist();
        // 得到当前移动位置是处于哪个点内
        lyjgesturepoint pointat = getpointat((int) event.getx(), (int) event.gety());
        if (currentpoint == null && pointat == null) {//你把手指按在屏幕滑动,如果终点与起点都不图片那么返回
          return true;
        } else {// 代表用户的手指移动到了点上
          if (currentpoint == null) {// 先判断当前的point是不是为null
            // 如果为空,那么把手指移动到的点赋值给currentpoint
            currentpoint = pointat;
            // 把currentpoint这个点设置选中状态;
            currentpoint.setpointstate(constants.point_state_selected);
          }
        }
        //如果移动到的点不为图片区域或者移动到自己的地方,或者该图片已经为选中状态,直接画直线就可以了
        if(pointat == null || currentpoint.equals(pointat) || constants.point_state_selected == pointat.getpointstate()){
          canvas.drawcircle(currentpoint.getcenterx(), currentpoint.getcentery(), 20, circlepaint);
          circlepoints.add(new lyjcirclepoint(currentpoint.getcenterx(), currentpoint.getcentery(), 20));
          canvas.drawline(currentpoint.getcenterx(), currentpoint.getcentery(), event.getx(), event.gety(), paint);
        }else{//其他情况画两点相连直线,并且保存绘制圆与直线,并调用按下图片的缩放动画
          canvas.drawcircle(pointat.getcenterx(),pointat.getcentery(),20,circlepaint);
          circlepoints.add(new lyjcirclepoint(pointat.getcenterx(), pointat.getcentery(), 20));
          this.animationcallback.startanimationimage(pointat.getnum());
          pointat.setpointstate(constants.point_state_selected);
          canvas.drawline(currentpoint.getcenterx(), currentpoint.getcentery(), pointat.getcenterx(), pointat.getcentery(), paint);
          pair<lyjgesturepoint, lyjgesturepoint> pair = new pair<>(currentpoint, pointat);
          linelist.add(pair);
          currentpoint=pointat;//设置选中点为当前点。
        }
        invalidate();//重绘
        break;
      case motionevent.action_up:
        clearscreenanddrawlist();//防止多出一条没有终点的直线
        new handler().postdelayed(new clearlinerunnable(), 1000);//1秒后清空绘制界面
        invalidate();//重绘
        break;
      default:
        break;
    }
    return true;
  }

  class clearlinerunnable implements runnable {
    public void run() {
      // 清空保存点与圆的集合
      linelist.clear();
      circlepoints.clear();
      // 重新绘制界面
      clearscreenanddrawlist();
      for (lyjgesturepoint p : list) {
        //设置其为初始化不选中状态
        p.setpointstate(constants.point_state_normal);
      }
      invalidate();
    }
  }

  /**
   * 通过点的位置去集合里面查找这个点是包含在哪个point里面的
   *
   * @param x
   * @param y
   * @return 如果没有找到,则返回null,代表用户当前移动的地方属于点与点之间
   */
  private lyjgesturepoint getpointat(int x, int y) {

    for (lyjgesturepoint point : list) {
      // 先判断点是否在图片的x坐标内
      int leftx = point.getpointlefttop().x;
      int rightx = point.getpointrightbottom().x;
      if (!(x >= leftx && x < rightx)) {
        // 如果为假,则跳到下一个对比
        continue;
      }
      //在判断点是否在图片的y坐标内
      int topy = point.getpointlefttop().y;
      int bottomy = point.getpointrightbottom().y;
      if (!(y >= topy && y < bottomy)) {
        // 如果为假,则跳到下一个对比
        continue;
      }

      // 如果执行到这,那么说明当前点击的点的位置在遍历到点的位置这个地方
      return point;
    }

    return null;
  }

  /**
   * 清掉屏幕上所有的线,然后画出集合里面的线
   */
  private void clearscreenanddrawlist() {
    canvas.drawcolor(color.transparent, porterduff.mode.clear);
    for (pair<lyjgesturepoint, lyjgesturepoint> pair : linelist) {
      canvas.drawline(pair.first.getcenterx(), pair.first.getcentery(),
          pair.second.getcenterx(), pair.second.getcentery(), paint);// 画线
    }
    for(lyjcirclepoint lyjcirclepoint : circlepoints){
      canvas.drawcircle(lyjcirclepoint.getroundx(),lyjcirclepoint.getroundy(), lyjcirclepoint.getradiu(),circlepaint);
    }
  }
  //绘制用bitmap创建出来的画布
  @override
  protected void ondraw(canvas canvas) {
    canvas.drawbitmap(bitmap, 0, 0, null);
  }
}

附上本文源码:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网