九宫格项目
功能介绍
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];
我在细说一下我的代码:
最后一个参数为接口,
- <pre name="code" class="java">public class CircleCanvas extends ListView {
- private Context mct;
- private Paint mpaint;
- private Paint hollowPaint;
- private Paint linePaint;
- private int width;
- private int height;
- private int startRangeWidth;
- private int startRangeHeight;
- private int endRangeWidth;
- private int endRangeHeight;
- private int spotIntervalWidth;
- private int spotIntervalHeight;
- private List<SpotXY> spot;
- private List<SpotXY> delSpot;
- private List<SpotXY> storeSpot;
- private List<Segment> segment;
- private int i=0;
- private float r=100.0f;
- private SpotXY xy;
- private SpotXY xyTwo;
- private int tclWay=0;
- private boolean isspot=true;
- private static int countId=1;
- private String pwd;
- private OnCircleCanvasOver oncirclecanvasover;
这个参数在储存画的线段的时候会用的,判断不要重复储存一样的线段
- private static int countId=1;
初始化操作,
- public CircleCanvas(Context context, AttributeSet attrs) {
- super(context, attrs);
- this.mct=context;
- spot=new ArrayList<SpotXY>();
- delSpot=new ArrayList<SpotXY>();
- storeSpot=new ArrayList<SpotXY>();
- segment=new ArrayList<Segment>();
- WindowManager wm=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- DisplayMetrics metric = new DisplayMetrics();
- wm.getDefaultDisplay().getMetrics(metric);
- intn();
- }
- public CircleCanvas(Context context) {
- super(context);
- this.mct=context;
- spot=new ArrayList<SpotXY>();
- delSpot=new ArrayList<SpotXY>();
- storeSpot=new ArrayList<SpotXY>();
- segment=new ArrayList<Segment>();
- WindowManager wm=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- DisplayMetrics metric = new DisplayMetrics();
- wm.getDefaultDisplay().getMetrics(metric);
- intn();
- }
- private void intn() {
- mpaint=new Paint();
- mpaint.setColor(Color.YELLOW );
- mpaint.setStrokeWidth(3);
- hollowPaint=new Paint();
- hollowPaint.setStyle(Paint.Style.STROKE);
- hollowPaint.setStrokeWidth(20);
- hollowPaint.setColor(Color.BLUE );
- linePaint=new Paint();
- linePaint.setColor(Color.GREEN );
- linePaint.setStrokeWidth(20);
-
- }
绘制,主要是这两个storeSpot为自己滑动过点的坐标集合,xy类型是SpotXY类这个是封装点的工具类。
有三参数x坐标 ,y坐标和点的id。上面表达式表示提出最近储存的点与即将要滑动的点画出线段。
- protected void onDraw(Canvas canvas)
- {
- switch(tclWay)
- {
- case 0:
- for(int i=0;i<spot.size();i++)
- {
- canvas.drawCircle(spot.get(i).getSpotx(),spot.get(i).getSpoty(), 30, mpaint);
- }
- break;
- case 1:
- for(int i=0;i<spot.size();i++)
- {
- canvas.drawCircle(spot.get(i).getSpotx(),spot.get(i).getSpoty(), 30, mpaint);
- }
- canvas.drawCircle(xy.getSpotx(), xy.getSpoty(), r, hollowPaint);
- delSpot(xy);
- break;
- case 2:
- for(int i=0;i<spot.size();i++)
- {
- canvas.drawCircle(spot.get(i).getSpotx(),spot.get(i).getSpoty(), 30, mpaint);
- }
- for(int i=0;i<storeSpot.size();i++)
- {
- canvas.drawCircle(storeSpot.get(i).getSpotx(), storeSpot.get(i).getSpoty(), r, hollowPaint);
- }
- for(int i=0;i<segment.size();i++)
- {
- canvas.drawLine(segment.get(i).getStartX(), segment.get(i).getStartY(), segment.get(i).getEndX(), segment.get(i).getEndY(), linePaint);
- }
-
- xy=storeSpot.get(storeSpot.size()-1);
- delSpot(xy);
-
- }
- super.onDraw(canvas);
- }
移除已近划过的点delSpot(xy)
-
-
-
-
- private void delSpot(SpotXY xy2) {
- for(int i=0;i<delSpot.size();i++)
- {
- if(xy.getSpotx()==delSpot.get(i).getSpotx()&&xy.getSpoty()==delSpot.get(i).getSpoty())
- {
- delSpot.remove(i);
- break;
- }
- }
- }
我是把手机分为4个区域,取中间相邻的两区域为手势可滑动区域。进而可以算出可以滑动区域的坐标,大小。
-
-
-
-
-
-
- private void glidingArea(int width2, int height2, int i) {
- startRangeWidth=0;
- startRangeHeight=height2/i;
- endRangeWidth=width2;
- endRangeHeight=height2*3/i;
- spotIntervalWidth=width2/6;
- spotIntervalHeight=Math.abs((endRangeHeight-startRangeHeight)/6);
-
- XYZ(startRangeWidth,startRangeHeight,endRangeWidth,endRangeHeight,spotIntervalWidth,spotIntervalHeight);
- for(SpotXY sxy:spot){
- delSpot.add(sxy);
-
- }
-
- }
countId是静态变量,在项目里不推崇大家用静态变量,这个id是在项目快要完成时加上的,想了一会只能用静态变量。
- <pre name="code" class="java"><pre name="code" class="java">
-
-
-
-
-
-
-
-
-
- private void XYZ(int startRangeWidth2, int startRangeHeight2,
- int endRangeWidth2, int endRangeHeight2,
- int spotIntervalWidth2, int spotIntervalHeight2) {
-
- for(int i=0;i<3;i++)
- {
- for(int j=0;j<3;j++)
- {
-
- spot.add(new SpotXY((int) (spotIntervalWidth2*(2*(j+1)-1)),
- (int) (startRangeHeight2+spotIntervalHeight2*(2*(i+1)-1)),countId++));
-
- }
-
- }
-
- }
这是判断点击点 和滑动的时候在不在可滑动区域,要是在返回最近点的坐标。
-
-
-
-
-
-
-
- private SpotXY latelyClick(float widthX, float widthY, List<SpotXY> spot2) {
- if(widthY<endRangeHeight&&widthY>startRangeHeight)
- {
- for(SpotXY spotxy:spot2)
- {
- if(Math.abs(spotxy.getSpotx()-widthX)<r&&Math.abs(spotxy.getSpoty()-widthY)<r)
- {
- return new SpotXY(spotxy.getSpotx(),spotxy.getSpoty(),spotxy.getId());
- }
- }
- }
- return null;
- }
下面事件处理份三处贴
记录点击点 并判断在不在可滑动区域内,在的画在最近的点加入storeSpot集合里(已经划过的点)。tclWay=1执行onDraw里的case 1; 刷新显示空心圆。
- public boolean onTouchEvent(MotionEvent event) {
- switch(event.getAction())
- {
- case MotionEvent.ACTION_DOWN:
- System.out.println("X变化为:"+event.getX());
-
- float widthX=event.getX();
- float widthY=event.getY();
- xy=latelyClick(widthX,widthY,spot);
- if(xy!=null)
- {
- storeSpot.add(xy);
- tclWay=1;
- invalidate();
- }
滑动时的事件处理,滑动的时候每时每刻都在判断是不是处在可滑动区域内,是否有新的点可以返回。如果有新点,还要遍历storeSpot集合看看里面有没有这个带没有就加入里面。然后在在这个点和上个点做为线段的两点加入到segment集合里。segment这个集合类型是Segment有四个参数即两个坐标点。tclWay变成2执行 onDraw画线段。
- case MotionEvent.ACTION_MOVE:
- System.out.println("X变化为:"+event.getX());
- float movewidthX=event.getX();
- float movewidthY=event.getY();
- xyTwo=latelyClick(movewidthX,movewidthY,spot);
- if(storeSpot.size()==0)
- {
- xy=xyTwo;
- }
- if(xyTwo!=null&&(xy.getSpotx()!=xyTwo.getSpotx()||xy.getSpoty()!=xyTwo.getSpoty()))
- {
-
- for(SpotXY sxy:storeSpot)
- {
-
- if(sxy.getSpotx()==xyTwo.getSpotx()&&sxy.getSpoty()==xyTwo.getSpoty())
- {
-
- isspot=false;
- break;
- }else{
- isspot=true;
- }
- }
- if(isspot)
- {
-
- if(storeSpot.size()>0)
- {
- segment.add(new Segment(xy.getSpotx(), xy.getSpoty(), xyTwo.getSpotx(), xyTwo.getSpoty()));
- }else{
- xy=xyTwo;
- }
- storeSpot.add(xyTwo);
- }
- tclWay=2;
- invalidate();
- }
- break;
回到以前,回到只有九个点的状态
- case MotionEvent.ACTION_UP:
- System.out.println("X变化为:"+event.getX());
- tclWay=0;
- setPwd();
- storeSpot.removeAll(storeSpot);
- segment.removeAll(segment);
- isspot=true;
- invalidate();
- break;
-
- }
- return true;
接口设计。
- public void setOnCircleCanvasOver(OnCircleCanvasOver oncirclecanvasover)
- {
- this.oncirclecanvasover=oncirclecanvasover;
- }
- public OnCircleCanvasOver getOnCircleCanvasOver()
- {
- return oncirclecanvasover;
-
- }
- public List<SpotXY> getStoreSpot() {
- return storeSpot;
- }
- public void setStoreSpot(List<SpotXY> storeSpot) {
- this.storeSpot = storeSpot;
- }
- public void setPwd()
- {
- pwd="123654789";
- oncirclecanvasover.Over(pwd);
- }
-
接口实现在MainActivity里面
- cecs=(CircleCanvas)findViewById(R.id.a);
- cecs.setOnCircleCanvasOver(new OnCircleCanvasOver() {
- public void Over(String pwd) {
- StringBuilder sb=new StringBuilder();
- List<SpotXY> list=cecs.getStoreSpot();
- for(SpotXY xy:list)
- {
- sb.append(xy.getId());
- }
- if(pwd.equals(sb.toString()))
- {
- Toast.makeText(getApplication(), "登陆成功"+pwd, Toast.LENGTH_LONG).show();
- }else
- {
-
- Toast.makeText(getApplication(), "两次输入不一样"+sb.toString(), Toast.LENGTH_LONG).show();
- }
- }
- );
- }