Android自定义view实现电影票在线选座功能

Android自定义view实现电影票在线选座功能,第1张

概述先看看电影票在线选座功能实现的效果图:界面比较粗糙,主要看原理。这个界面主要包括以下几部分

先看看电影票在线选座功能实现的效果图:

界面比较粗糙,主要看原理。

这个界面主要包括以下几部分

1、座位
2、左边的排数
3、左上方的缩略图
4、缩略图中的红色区域
5、手指移动时跟随移动
6、两个手指缩放时跟随缩放

主要技术点

1、矩阵Matrix
2、GestureDetector与ScaleGestureDetector
3、Bitmap的一下基本用法
4、这里只需要重写vIEw的onDraw就可实现全部功能

可以发现这个其实没什么难度,主要就是一些位置的计算。

为了能便于理解首先把要用到的知识点进行一下梳理

1、矩阵Matrix

Matrix由3*3矩阵中9个值来决定,我们对Matrix的所有设置, 就是对这9个值的 *** 作。

{MSCALE_X,MSKEW_X,MTRANS_X,
MSKEW_Y,MSCALE_Y,MTRANS_Y,
MPERSP_0,MPERSP_1,MPERSP_2}

这是矩阵的9个值,看名字也知道他们是什么意思了。

这里主要用到缩放和平移,下面以缩放为例来了解一下缩放的控制
通过AndroID提供的API我们可以调用setScale、preScale、postscale来改变MSCALE_X和MSCALE_Y的值达到缩放的效果

所以只要理解setScale、preScale、postscale这三个方法的区别我们就可以简单的进行缩放控制了

1、setScale(sx,sy),首先会将该Matrix设置为对角矩阵,即相当于调用reset()方法,然后在设置该Matrix的MSCALE_X和MSCALE_Y直接设置为sx,sy的值
2、preScale(sx,sy),不会重置Matrix,而是直接与Matrix之前的MSCALE_X和MSCALE_Y值结合起来(相乘),M' = M * S(sx,sy)。
3、postscale(sx,sy),不会重置Matrix,而是直接与Matrix之前的MSCALE_X和MSCALE_Y值结合起来(相乘),M' = S(sx,sy) * M。

这么说其实也有些不好理解,举个栗子一看就明白

1、pre….的执行顺序

 Matrix matrix=new Matrix(); float[] points=new float[]{10.0f,10.0f}; matrix.preScale(2.0f,3.0f); matrix.preTranslate(8.0f,7.0f); matrix.mapPoints(points); Log.i("test",points[0]+""); Log.i("test",points[1]+"");

结果为点坐标为(36.0,51.0)
可以得出结论,进行变换的顺序是先执行preTranslate(8.0f,7.0f),在执行的preScale(2.0f,3.0f)。即对于一个Matrix的设置中,所有pre….是倒着向后执行的。

2、post…的执行顺序

 Matrix matrix=new Matrix(); float[] points=new float[]{10.0f,10.0f}; matrix.postscale(2.0f,3.0f); matrix.postTranslate(8.0f,points[1]+"");

结果为点坐标为(28.0,37.0)
可以得出结论,进行变换的顺序是先执行postscale(2.0f,3.0f),在执行的postTranslate(8.0f,7.0f)。即对于一个Matrix的设置中,所有post….是顺着向前执行的。

这里主要知道set…和post…方法就行,因为只用到了这两个。
自我理解其实和scrollTo、scrollBy类似。

2、GestureDetector与ScaleGestureDetector

GestureDetector主要用于识别一些特定手势,只要调用GestureDetector.ontouchEvent()把MotionEvent传递进去就可以了
ScaleGestureDetector用于处理缩放的攻击类用法和GestureDetector类似

3、Bitmap的一下基本用法
参考: 关于bitmap你不知道的一些事

了解一下bitmap的注意事项即可

下面开始正式画这个选座的功能了

1、画座位:

@OverrIDe protected voID onDraw(Canvas canvas) { super.onDraw(canvas); /** * 如果第一次进入 使座位图居中 */ if (mVIEwH != 0 && mVIEwW != 0&&isFrist) { isFrist = false; matrix.setTranslate(-(mVIEwW-getMeasureDWIDth())/2,0); } /** * 画座位 */ drawSeat(canvas); /** * 画排数 */ drawText(canvas); /** * 画缩略图 */ drawOverVIEw(canvas); /** * 画缩略图选择区域 */ drawOvewRect(canvas); }
private voID drawSeat(Canvas canvas) { float zoom = getMatrixScaleX(); scale1 = zoom; tranlateX = getTranslateX(); tranlateY = getTranslateY(); /** * 使用两层for循环来画出所有座位 */ for (int i = 0; i < row; i++) { float top = i * SeatHight * scale * scale1 + i * mSpaceY * scale1 + tranlateY; for (int j = 0; j < column; j++) { float left = j * SeatWIDth * scale * scale1 + j * mSpaceX * scale1 + tranlateX; tempMatrix.setTranslate(left,top); tempMatrix.postscale(scale,scale,left,top); tempMatrix.postscale(scale1,scale1,top); /** * 获取每个位置的信息 */ int state = getSeatType(i,j); /** * 根据位置信息画不同的位置图片 */ switch (state) { case SEAT_TYPE_SolD: canvas.drawBitmap(SeatLock,tempMatrix,null); break; case SEAT_TYPE_SELECTED: canvas.drawBitmap(SeatChecked,null); break; case SEAT_TYPE_AVAILABLE: canvas.drawBitmap(Seatnormal,null); break; case SEAT_TYPE_NOT_AVAILABLE: break; } } } }

这里其实没什么难度,主要就是使用两层for循环,一层画行,一层画列

另外要注意的就是当前位置的计算 top = (当前位置i)(座位图标大小SeatHight 它本身的缩放比scale*缩放时的缩放比scale1)+(当前位置i* 垂直方向的间距mSpaceY*缩放时的缩放比scale1)+垂直方向移动是的移动距离

2、画排数

private voID drawText(Canvas canvas) { mTextPaint.setcolor(baccolor); RectF rectF = new RectF(); rectF.top = getTranslateY() - mNumberHeight/2; rectF.bottom = getTranslateY()+ mVIEwH* getMatrixScaleX() + mNumberHeight/2; rectF.left = 0; rectF.right = mTextWIDth; canvas.drawRoundRect(rectF,mTextWIDth/2,mTextPaint); mTextPaint.setcolor(color.WHITE); for (int i = 0; i < row; i++) { float top = (i *SeatHight*scale + i * mSpaceY) * getMatrixScaleX() + getTranslateY(); float bottom = (i * SeatHight*scale + i * mSpaceY + SeatHight) * getMatrixScaleX() + getTranslateY(); float baseline = (bottom + top - lineNumberPaintFontMetrics.bottom - lineNumberPaintFontMetrics.top ) / 2-6; canvas.drawText(lineNumbers.get(i),mTextWIDth / 2,baseline,mTextPaint); }  }

3、画缩略图

private voID drawOverVIEw(Canvas canvas) { /** * 1、先画张背景图片 */ mBitMapOverVIEw = Bitmap.createBitmap((int)mOverVIEwWIDth,(int)mOverVIEwHight,Bitmap.Config.ARGB_8888); Canvas OverVIEwCanvas = new Canvas(mBitMapOverVIEw); Paint paint = new Paint(); paint.setcolor(baccolor); scaleoverX = mOverVIEwWIDth / mVIEwW; scaleoverY = mOverVIEwHight / mVIEwH; float tempX = mVIEwW * scaleoverX; float tempY = mVIEwH * scaleoverY; OverVIEwCanvas.drawRect(0,(float)tempX,(float)tempY,paint); Matrix tempoverMatrix = new Matrix(); /** * 2、和画座位图一样在缩略图中画座位 */ for (int i = 0; i < row; i++) { float top = i * SeatHight * scale * scaleoverY+ i * mSpaceY * scaleoverY; for (int j = 0; j < column; j++) { float left = j * SeatWIDth * scale * scaleoverX + j * mSpaceX * scaleoverX+mTextWIDth*scaleoverX; tempoverMatrix.setTranslate(left,top); tempoverMatrix.postscale(scale*scaleoverX,scale*scaleoverY,top); int state = getSeatType(i,j); switch (state) { case SEAT_TYPE_SolD: OverVIEwCanvas.drawBitmap(SeatLock,tempoverMatrix,null); break; case SEAT_TYPE_SELECTED: OverVIEwCanvas.drawBitmap(SeatChecked,null); break; case SEAT_TYPE_AVAILABLE: OverVIEwCanvas.drawBitmap(Seatnormal,null); break; case SEAT_TYPE_NOT_AVAILABLE: break; } } } canvas.drawBitmap(mBitMapOverVIEw,null); }

4、缩略图中的红色区域

private voID drawOvewRect(Canvas canvas) { OverRectPaint = new Paint(); OverRectPaint.setcolor(color.RED); OverRectPaint.setStyle(Paint.Style.stroke); OverRectPaint.setstrokeWIDth(overRectlinewidth); int tempVIEwW ; int tempVIEwH; if(getMeasureDWIDth()<mVIEwW){ tempVIEwW = getMeasureDWIDth(); }else{ tempVIEwW = mVIEwW; } if(getMeasuredHeight()<mVIEwH){ tempVIEwH = getMeasuredHeight(); }else{ tempVIEwH = mVIEwH; } try{ Rect rect ; if(getMatrixScaleX()>= 1.0f){ rect = new Rect((int)(scaleoverX*Math.abs(getTranslateX())/getMatrixScaleX()),(int)(scaleoverY*Math.abs(getTranslateY())/getMatrixScaleX()),(int)(scaleoverX*Math.abs(getTranslateX())/getMatrixScaleX()+tempVIEwW*scaleoverX/getMatrixScaleX()),(int)(scaleoverY*Math.abs(getTranslateY())/getMatrixScaleX()+tempVIEwH*scaleoverY/getMatrixScaleX())); }else{ rect = new Rect((int)(scaleoverX*Math.abs(getTranslateX())),(int)(scaleoverY*Math.abs(getTranslateY())),(int)(scaleoverX*Math.abs(getTranslateX())+tempVIEwW*scaleoverX),(int)(scaleoverY*Math.abs(getTranslateY())+tempVIEwH*scaleoverY)); } canvas.drawRect(rect,OverRectPaint); }catch(Exception e){ e.printstacktrace(); }  }

5、手指移动时跟随移动

@OverrIDe public boolean ontouchEvent(MotionEvent event) { /** * 缩放事件交由ScaleGestureDetector处理 */ scaleGestureDetector.ontouchEvent(event); /** * 移动和点击事件交由GestureDetector处理 */ gestureDetector.ontouchEvent(event); return true; }
/** * 移动事件 这里只是简单判断了一下,需要更细致的进行条件判断 */ public boolean onScroll(MotionEvent e1,MotionEvent e2,float distanceX,float distanceY) { float tempMVIEwW = column * SeatWIDth*scale*scale1+(column -1)*mSpaceX*scale1+mTextWIDth-getWIDth(); float tempmVIEwH = row * SeatHight * scale * scale1 + (row -1) * mSpaceY * scale1 - getHeight(); if((getTranslateX()>mTextWIDth+mSpaceX)&& distanceX<0){ distanceX = 0.0f; } if((Math.abs(getTranslateX())>tempMVIEwW)&&(distanceX>0)){ distanceX = 0.0f; } if((getTranslateY()>0)&&distanceY<0){ distanceY=0.0f; } if((Math.abs(getTranslateY())>tempmVIEwH)&&(distanceY>0)){ distanceY = 0.0f; }  matrix.postTranslate(-distanceX,-distanceY);  invalIDate(); return false; } /** * 单击事件 */ public boolean onSingleTapConfirmed(MotionEvent e) { int x = (int) e.getX(); int y = (int) e.getY(); for (int i = 0; i < row; i++) { for (int j = 0; j < column; j++) { int tempX = (int) ((j * SeatWIDth * scale + j * mSpaceX) * getMatrixScaleX() + getTranslateX()); int maxTemX = (int) (tempX + SeatWIDth * scale * getMatrixScaleX()); int tempY = (int) ((i * SeatHight * scale + i * mSpaceX) * getMatrixScaleY() + getTranslateY()); int maxTempY = (int) (tempY + SeatHight * scale * getMatrixScaleY()); if (x >= tempX && x <= maxTemX && y >= tempY  && y <= maxTempY) { int ID = getID(i,j); int index = isHave(ID); if (index >= 0) {  remove(index); } else {  addChooseSeat(i,j); } float currentScaleY = getMatrixScaleY(); if (currentScaleY < 1.7f) {  scaleX = x;  scaleY = y;  /**  * 选中时进行缩放 *** 作  */  zoomAnimate(currentScaleY,1.9f); } invalIDate(); break; } } } return super.onSingleTapConfirmed(e); } });

6、两个手指缩放时跟随缩放

public boolean onScale(ScaleGestureDetector detector) { float scaleFactor = detector.getScaleFactor(); //scaleX = detector.getCurrentSpanX(); //scaleY = detector.getCurrentSpanY(); //直接判断大于2会导致获取的matrix缩放比例继续执行一次从而导致变成2.000001之类的数从而使 //判断条件一直为真从而不会执行缩小动作 //判断相乘大于2 可以是当前获得的缩放比例即使是1.9999之类的数如果继续放大即使乘以1.0001也会比2大从而 //避免上述问题。 if (getMatrixScaleY() * scaleFactor > 2) { scaleFactor = 2 / getMatrixScaleY(); } if (getMatrixScaleY() * scaleFactor < 0.8) { scaleFactor = 0.8f / getMatrixScaleY(); } matrix.postscale(scaleFactor,scaleFactor); invalIDate(); return true; }

至此这个比较粗糙的选座功能就实现了,有时间会继续优化下细节问题。

下面两个demo都比较给力我就不上传demo了。

参考资料:

Android选座源码解析

 Andriod 打造炫酷的电影票在线选座控件,1比1还原淘宝电影在线选座功能

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Android自定义view实现电影票在线选座功能全部内容,希望文章能够帮你解决Android自定义view实现电影票在线选座功能所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1147775.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存