热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

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 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 

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 list;
  /***
   * 记录画过的线
   */
  private List> lineList;
  /***
   * 记录画过的圆
   */
  private List 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 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 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 = topY && y  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有所帮助。


推荐阅读
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 本文介绍了一些好用的搜索引擎的替代品,包括网盘搜索工具、百度网盘搜索引擎等。同时还介绍了一些笑话大全、GIF笑话图片、动态图等资源的搜索引擎。此外,还推荐了一些迅雷快传搜索和360云盘资源搜索的网盘搜索引擎。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 众筹商城与传统商城的区别及php众筹网站的程序源码
    本文介绍了众筹商城与传统商城的区别,包括所售产品和玩法不同以及运营方式不同。同时还提到了php众筹网站的程序源码和方维众筹的安装和环境问题。 ... [详细]
author-avatar
962326154_5af7cb
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有