软件编程
位置:首页>> 软件编程>> Android编程>> Android仿百度福袋红包界面

Android仿百度福袋红包界面

作者:Git_Android  发布时间:2023-11-01 04:53:01 

标签:Android,红包

首先来看一下效果图:

Android仿百度福袋红包界面

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仿百度福袋红包界面

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com