首页 > 系统 > Android > 正文

Android仿百度福袋红包界面

2020-04-11 10:52:20
字体:
来源:转载
供稿:网友

首先来看一下效果图:

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);  }}

这样就可以得到如下界面效果(当然反编译百度钱包,并没有百度钱包中的图片,只好随便找了一张图片):

以上就是本文的全部内容,希望对大家学习Android有所帮助。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表