九宫格项目二

本文介绍了Android开发中实现九宫格布局的步骤,包括XML编辑和自定义View。同时,讲解了一个密码锁定控件的设计,涉及点选判断、线绘制和动画效果,以及数据存储。此外,还分享了项目开发过程中的难点和解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

九宫格项目

功能介绍

1.点击某圆圈后,在该圆圈的中心添加一个实行的小圆 
2.页面滑动出现一条跟随的线 
3.滑动到另一个圆圈时,产生一条连接的直线 
4.选择的圆圈点数大于等于4个后,手指抬起,就会保存密码。 

涉及到的知识点

· 本示例使用的是自定义的View来绘制九宫格,并保存图像

· 这里的九个点分别代表的是九个数值,获取到对应的数值证明绘制了那个点

· 程序中使用到的知识:

· 1、图像的描绘,圆和点的描绘,线的描绘

· 2、位置的判断,判断用户点的位置是否在某一个圆内

· 3、保存数据和相关判断是否保存密码。

最近正在制作第一个Android开发菜单项目,最开始我在设计首页的时候采用的是最原始的Layout布局方式,重复的写了很多的布局代码,显得尤为臃肿和繁琐。这显然和Android UI设计讲求简洁的特性不符合,也让我对重复的代码很是不感冒。

然后想起冯君老师曾经讲过类似的问题,可以使用GridVIew表格布局来设计九宫格,使UI的首页设计更加简洁大方。

第一步编辑mian.xml

这是九宫格的整体布局显示,设计想设计的九宫格的行和列。如果你认为九宫格就是只有3x3格局,这是错误的。

在设计的过程中,我将numColumns的值设计为"3",因为每行显示3个图标感觉是最好看的。如果numColumns的值设计为auto_fit,在行未满的时候,会自动的帮你填充行。

第二步,编辑item.xml

   编辑item.xml时我采用了相对布局的方式,表示的是九宫格里的每一个小格的布局特性,用迭代的方法可以重复的将单个小格填充到九宫格的中体布局中区。

   imageView控件,表示小格的图片显示信息,包括图片的长、宽、名字、ID等。TextView控件管理文字信息,text的值会在UI界面上显示。

第三步实现九宫格布局

   实现九宫格的布局显示,这里会使用到Java语言,不会Java的话,那你的Android开发路程就算完了。

需要设置适配器Adapter,用来对每个单元格实现一一对应的图片和文字说明。我在这里先使用了两个数组,分别对单元格的图片和文字定义。然后就是九宫格具体显示问题编写imageAdapter类。

 这里我只是对项目的首页UI布局进行了一个简要的总结,因为是第一次做项目,难免会又不足。

前言:随着社会的快速发展,金融行业也迅速发展。对于金融行业开发的App或者其他软件安全要求都比较高。为此,开发商为了提高App的安全性进行再App里面添加锁屏界面,为用户的安全,大大的增加可靠性。

第一:控件的结构 控件是有 导航、原点、状态提示三部分组成。

1.导航是系统导航;

2.原点可以有好多中创建方法(比如:UIButton/UIview/UIImageView等等),本控件选择Button。

3.状态提示为UIlabel,并添加基础动画。

第二:控件涉及到的知识点。

1.判断一个点是否在一个区域里面,使用函数CGRectContainsPoint。(这里,留下一个问题,自己做实验,如果该区域被裁减了,然后使用函数,取裁减区域的点,是否是在区域里面?)。

2. 如何巧妙的给一个父类的相同子类,添加标记,并区分子类。

3.UIView的一些方法的从写。比如-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event、-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event、-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event。

4.如何获取手势点击的坐标点。使用方法:locationInView。是UItouch 的方法。

5.数组里面可以存储什么类型的对象?

6.结构体转为对象,对象转为结构体。本列是 CGpoint /NSValue 的转化。

7.从数组中获取信息,转化为字符串。

8.基础动画CABasicAnimation的使用。本例是动画的抖动。如何让动画再次开启动画?

9. Quartz2D的绘制。

10.数据密码的存储。

第三:控件设计过程中的难点。

       1.控件中的原点,如何选择哪一个控件。

       2.第一次点击获取坐标,不是原点区域不进行绘制。

       3.获取点是原点的时候,原点进行颜色变换。

       4.在绘制路线的时候,进行手势跟踪绘制。

       5.在绘制完成的时候,路线毛边的祛除。

       6.绘制完的路线,如何清除绘制的路线。

       7.绘制点的排重复。

第四:控件的效果。


       

第五:控件的调用方法。

       控件调用非常简单,只要两行代码就可以。

    GesturespasswordView * GesturesView = [[GesturespasswordView alloc]initWithFrame:self.view.frame];

    [[UIApplication sharedApplication].keyWindow addSubview:GesturesView];

我在细说一下我的代码:

[java]  view plain  copy
  1.   

最后一个参数为接口,

[java]  view plain  copy
  1. <pre name="code" class="java">public class CircleCanvas extends ListView {  
  2.     private Context mct;  
  3.     private Paint mpaint;                      //画笔  
  4.     private Paint hollowPaint;  
  5.     private Paint linePaint;  
  6.     private int width;                         //view  宽,高  
  7.     private int height;  
  8.     private int startRangeWidth;               //起点坐标(x,y)  
  9.     private int startRangeHeight;  
  10.     private int endRangeWidth;                 //终点坐标(X,Y)两个坐标构成滑动区域。  
  11.     private int endRangeHeight;  
  12.     private int spotIntervalWidth;             //每个点之间的间隔  
  13.     private int spotIntervalHeight;    
  14.     private List<SpotXY> spot;                 //存放9个点的坐标  
  15.     private List<SpotXY> delSpot;              //作用方面显示画的结果  
  16.     private List<SpotXY> storeSpot;            //储存选中的空心圆的坐标  即spot  
  17.     private List<Segment> segment;             //储存画出的线段     
  18.     private int i=0;  
  19.     private float r=100.0f;                    //大圆半径  
  20.     private SpotXY xy;                         //一个点  
  21.     private SpotXY xyTwo;  
  22.     private int tclWay=0;  
  23.     private boolean isspot=true;  
  24.     private static int countId=1;                     //每个点的id编号  
  25.     private String pwd;                        //密码  
  26.     private OnCircleCanvasOver oncirclecanvasover;  

 
这个参数在储存画的线段的时候会用的,判断不要重复储存一样的线段 

[java]  view plain  copy
  1. private static int countId=1;                     //每个点的id编号  

初始化操作,

[java]  view plain  copy
  1. public CircleCanvas(Context context, AttributeSet attrs) {  
  2.     super(context, attrs);  
  3.     this.mct=context;  
  4.     spot=new ArrayList<SpotXY>();  
  5.     delSpot=new ArrayList<SpotXY>();  
  6.     storeSpot=new ArrayList<SpotXY>();  
  7.     segment=new ArrayList<Segment>();  
  8.     WindowManager wm=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);  
  9.     DisplayMetrics metric = new DisplayMetrics();    
  10.     wm.getDefaultDisplay().getMetrics(metric);    
  11.     intn();  
  12. }  
  13. public CircleCanvas(Context context) {  
  14.     super(context);  
  15.     this.mct=context;  
  16.     spot=new ArrayList<SpotXY>();  
  17.     delSpot=new ArrayList<SpotXY>();  
  18.     storeSpot=new ArrayList<SpotXY>();  
  19.     segment=new ArrayList<Segment>();  
  20.     WindowManager wm=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);  
  21.     DisplayMetrics metric = new DisplayMetrics();    
  22.     wm.getDefaultDisplay().getMetrics(metric);    
  23.     intn();  
  24. }  
  25. private void intn() {  
  26.     mpaint=new Paint();  
  27.     mpaint.setColor(Color.YELLOW );  
  28.     mpaint.setStrokeWidth(3);  
  29.     hollowPaint=new Paint();  
  30.     hollowPaint.setStyle(Paint.Style.STROKE);  
  31.     hollowPaint.setStrokeWidth(20);  
  32.     hollowPaint.setColor(Color.BLUE );  
  33.     linePaint=new Paint();  
  34.     linePaint.setColor(Color.GREEN );  
  35.     linePaint.setStrokeWidth(20);  
  36.       
  37. }  

绘制,主要是这两个storeSpot为自己滑动过点的坐标集合,xy类型是SpotXY类这个是封装点的工具类。

有三参数x坐标 ,y坐标和点的id。上面表达式表示提出最近储存的点与即将要滑动的点画出线段。

[java]  view plain  copy
  1. protected void onDraw(Canvas canvas)  
  2. {  
  3.     switch(tclWay)  
  4.     {  
  5.         case 0:  
  6.             for(int i=0;i<spot.size();i++)  
  7.             {  
  8.                 canvas.drawCircle(spot.get(i).getSpotx(),spot.get(i).getSpoty(), 30, mpaint);  
  9.             }  
  10.                    break;  
  11.         case 1:  
  12.             for(int i=0;i<spot.size();i++)  
  13.             {  
  14.                 canvas.drawCircle(spot.get(i).getSpotx(),spot.get(i).getSpoty(), 30, mpaint);  
  15.             }  
  16.             canvas.drawCircle(xy.getSpotx(), xy.getSpoty(), r, hollowPaint);  
  17.             delSpot(xy);  
  18.                 break;  
  19.         case 2:  
  20.             for(int i=0;i<spot.size();i++)  
  21.             {  
  22.                 canvas.drawCircle(spot.get(i).getSpotx(),spot.get(i).getSpoty(), 30, mpaint);  
  23.             }  
  24.             for(int i=0;i<storeSpot.size();i++)  
  25.             {  
  26.                 canvas.drawCircle(storeSpot.get(i).getSpotx(), storeSpot.get(i).getSpoty(), r, hollowPaint);  
  27.             }  
  28.             for(int i=0;i<segment.size();i++)  
  29.             {  
  30.                 canvas.drawLine(segment.get(i).getStartX(), segment.get(i).getStartY(), segment.get(i).getEndX(), segment.get(i).getEndY(), linePaint);  
  31.             }  
  32.               
  33.             xy=storeSpot.get(storeSpot.size()-1);  
  34.             delSpot(xy);  
  35.       
  36.     }  
  37.     super.onDraw(canvas);  
  38. }  

移除已近划过的点delSpot(xy)

[java]  view plain  copy
  1. /** 
  2.  * 移除被选中的点 
  3.  * @param xy2 
  4.  */  
  5.  private void delSpot(SpotXY xy2) {  
  6.      for(int i=0;i<delSpot.size();i++)  
  7.      {  
  8.          if(xy.getSpotx()==delSpot.get(i).getSpotx()&&xy.getSpoty()==delSpot.get(i).getSpoty())  
  9.          {  
  10.              delSpot.remove(i);  
  11.              break;  
  12.          }  
  13.      }  
  14. }  

  我是把手机分为4个区域,取中间相邻的两区域为手势可滑动区域。进而可以算出可以滑动区域的坐标,大小。

[java]  view plain  copy
  1. /** 
  2.  * 计算有效滑动区域 
  3.  * @param width2     view 宽 
  4.  * @param height2    view 高 
  5.  * @param i          区域划分的个数   
  6.  */  
  7. private void glidingArea(int width2, int height2, int i) {  
  8.     startRangeWidth=0;   
  9.     startRangeHeight=height2/i;  
  10.     endRangeWidth=width2;  
  11.     endRangeHeight=height2*3/i;  
  12.     spotIntervalWidth=width2/6;  
  13.     spotIntervalHeight=Math.abs((endRangeHeight-startRangeHeight)/6);  
  14.     //countId=0;  
  15.     XYZ(startRangeWidth,startRangeHeight,endRangeWidth,endRangeHeight,spotIntervalWidth,spotIntervalHeight);  
  16.     for(SpotXY sxy:spot){  
  17.         delSpot.add(sxy);  
  18.           
  19.     }  
  20.       
  21. }  

countId是静态变量,在项目里不推崇大家用静态变量,这个id是在项目快要完成时加上的,想了一会只能用静态变量。

[java]  view plain  copy
  1. <pre name="code" class="java"><pre name="code" class="java">    /** 
  2.      * 计算9个点的坐标 
  3.      * @param startRangeWidth2 
  4.      * @param startRangeHeight2 
  5.      * @param endRangeWidth2 
  6.      * @param endRangeHeight2 
  7.      * @param spotIntervalWidth2 
  8.      * @param spotIntervalHeight2 
  9.      * @return 
  10.      */  
  11.     private void XYZ(int startRangeWidth2, int startRangeHeight2,  
  12.             int endRangeWidth2, int endRangeHeight2,  
  13.             int spotIntervalWidth2, int spotIntervalHeight2) {  
  14.           
  15.         for(int i=0;i<3;i++)  
  16.         {  
  17.             for(int j=0;j<3;j++)  
  18.             {  
  19.                   
  20.                     spot.add(new SpotXY((int) (spotIntervalWidth2*(2*(j+1)-1)),  
  21.                             (int) (startRangeHeight2+spotIntervalHeight2*(2*(i+1)-1)),countId++));  
  22.                   
  23.             }  
  24.               
  25.         }  
  26.         //return spot;  
  27.     }  

 
 

这是判断点击点 和滑动的时候在不在可滑动区域,要是在返回最近点的坐标。

[java]  view plain  copy
  1. /** 
  2.  * 返回离点击点最近的点 
  3.  * @param widthX 
  4.  * @param widthY 
  5.  * @param spot2 
  6.  * @return 
  7.  */  
  8. private SpotXY latelyClick(float widthX, float widthY, List<SpotXY> spot2) {  
  9.     if(widthY<endRangeHeight&&widthY>startRangeHeight)  
  10.     {  
  11.         for(SpotXY spotxy:spot2)  
  12.         {  
  13.             if(Math.abs(spotxy.getSpotx()-widthX)<r&&Math.abs(spotxy.getSpoty()-widthY)<r)  
  14.             {  
  15.                 return new SpotXY(spotxy.getSpotx(),spotxy.getSpoty(),spotxy.getId());  
  16.             }  
  17.         }  
  18.     }  
  19.     return null;  
  20. }  

下面事件处理份三处贴

记录点击点 并判断在不在可滑动区域内,在的画在最近的点加入storeSpot集合里(已经划过的点)。tclWay=1执行onDraw里的case 1; 刷新显示空心圆。

[java]  view plain  copy
  1. public boolean onTouchEvent(MotionEvent event) {  
  2.     switch(event.getAction())  
  3.     {  
  4.         case MotionEvent.ACTION_DOWN:  
  5.             System.out.println("X变化为:"+event.getX());  
  6.             //invalidate();  
  7.             float widthX=event.getX();  
  8.             float widthY=event.getY();  
  9.              xy=latelyClick(widthX,widthY,spot);  
  10.             if(xy!=null)  
  11.             {  
  12.                 storeSpot.add(xy);  
  13.                 tclWay=1;  
  14.                 invalidate();  
  15.             }             

滑动时的事件处理,滑动的时候每时每刻都在判断是不是处在可滑动区域内,是否有新的点可以返回。如果有新点,还要遍历storeSpot集合看看里面有没有这个带没有就加入里面。然后在在这个点和上个点做为线段的两点加入到segment集合里。segment这个集合类型是Segment有四个参数即两个坐标点。tclWay变成2执行 onDraw画线段。

[java]  view plain  copy
  1. case MotionEvent.ACTION_MOVE:  
  2.         System.out.println("X变化为:"+event.getX());  
  3.         float movewidthX=event.getX();  
  4.         float movewidthY=event.getY();  
  5.         xyTwo=latelyClick(movewidthX,movewidthY,spot);  
  6.         if(storeSpot.size()==0)                               //当点击不在规定范围时, 滑动到规定范围里执行次判断  
  7.         {  
  8.             xy=xyTwo;  
  9.         }  
  10.         if(xyTwo!=null&&(xy.getSpotx()!=xyTwo.getSpotx()||xy.getSpoty()!=xyTwo.getSpoty()))  
  11.         {  
  12.               
  13.              for(SpotXY sxy:storeSpot)  
  14.                 {    
  15.                       
  16.                     if(sxy.getSpotx()==xyTwo.getSpotx()&&sxy.getSpoty()==xyTwo.getSpoty())  
  17.                     {  
  18.                         //storeSpot.add(xyTwo);  
  19.                         isspot=false;  
  20.                         break;  
  21.                     }else{  
  22.                         isspot=true;  
  23.                     }  
  24.                 }  
  25.              if(isspot)  
  26.              {  
  27.                   
  28.                  if(storeSpot.size()>0)  
  29.                  {  
  30.                      segment.add(new Segment(xy.getSpotx(), xy.getSpoty(), xyTwo.getSpotx(), xyTwo.getSpoty()));  
  31.                  }else{  
  32.                      xy=xyTwo;  
  33.                  }  
  34.                  storeSpot.add(xyTwo);  
  35.              }  
  36.             tclWay=2;  
  37.             invalidate();  
  38.         }  
  39.         break;  

回到以前,回到只有九个点的状态

[java]  view plain  copy
  1. case MotionEvent.ACTION_UP:  
  2.             System.out.println("X变化为:"+event.getX());  
  3.             tclWay=0;  
  4.             setPwd();  
  5.             storeSpot.removeAll(storeSpot);  
  6.             segment.removeAll(segment);  
  7.             isspot=true;  
  8.             invalidate();  
  9.             break;  
  10.       
  11.     }  
  12.     return true;  

接口设计。

[java]  view plain  copy
  1. public void setOnCircleCanvasOver(OnCircleCanvasOver oncirclecanvasover)  
  2.     {  
  3.         this.oncirclecanvasover=oncirclecanvasover;  
  4.     }  
  5.     public OnCircleCanvasOver getOnCircleCanvasOver()  
  6.     {  
  7.         return oncirclecanvasover;  
  8.           
  9.     }  
  10.     public List<SpotXY> getStoreSpot() {  
  11.         return storeSpot;  
  12.     }  
  13.     public void setStoreSpot(List<SpotXY> storeSpot) {  
  14.         this.storeSpot = storeSpot;  
  15.     }  
  16.     public void setPwd()  
  17.     {  
  18.         pwd="123654789";  
  19.         oncirclecanvasover.Over(pwd);  
  20.     }  
  21.       
接口实现在MainActivity里面

[java]  view plain  copy
  1.   cecs=(CircleCanvas)findViewById(R.id.a);  
  2.      cecs.setOnCircleCanvasOver(new OnCircleCanvasOver() {  
  3. public void Over(String pwd) {  
  4.     StringBuilder sb=new StringBuilder();  
  5.     List<SpotXY> list=cecs.getStoreSpot();  
  6.     for(SpotXY xy:list)  
  7.     {  
  8.         sb.append(xy.getId());  
  9.     }  
  10.     if(pwd.equals(sb.toString()))  
  11.     {  
  12.         Toast.makeText(getApplication(), "登陆成功"+pwd, Toast.LENGTH_LONG).show();  
  13.     }else  
  14.     {  
  15.           
  16.         Toast.makeText(getApplication(), "两次输入不一样"+sb.toString(), Toast.LENGTH_LONG).show();  
  17.     }  
  18. }  
  19. );  
  20.  }  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值