首先先看一下效果图

这里只是简单的实现了这个效果,具体的思路以及知识点我个人还是不怎么理解下面的俩个连接多看一下

https://www.cnblogs.com/itgungnir/p/6217447.html?tdsourcetag=s_pcqq_aiomsg

https://blog.csdn.net/lmj623565791/article/details/45022631/

第一步:

写自定义view的类

public class SeatTable extends View {private final boolean DBG = false;Paint paint = new Paint();Paint overviewPaint=new Paint();Paint lineNumberPaint;float lineNumberTxtHeight;/*** 设置行号 默认显示 1,2,3....数字* @param lineNumbers*/public void setLineNumbers(ArrayList<String> lineNumbers) {this.lineNumbers = lineNumbers;invalidate();}/*** 用来保存所有行号*/ArrayList<String> lineNumbers = new ArrayList<>();Paint.FontMetrics lineNumberPaintFontMetrics;Matrix matrix = new Matrix();/*** 座位水平间距*/int spacing;/*** 座位垂直间距*/int verSpacing;/*** 行号宽度*/int numberWidth;/*** 行数*/int row;/*** 列数*/int column;/*** 可选时座位的图片*/Bitmap seatBitmap;/*** 选中时座位的图片*/Bitmap checkedSeatBitmap;/*** 座位已经售出时的图片*/Bitmap seatSoldBitmap;Bitmap overviewBitmap;int lastX;int lastY;/*** 整个座位图的宽度*/int seatBitmapWidth;/*** 整个座位图的高度*/int seatBitmapHeight;/*** 标识是否需要绘制座位图*/boolean isNeedDrawSeatBitmap = true;/*** 概览图白色方块高度*/float rectHeight;/*** 概览图白色方块的宽度*/float rectWidth;/*** 概览图上方块的水平间距*/float overviewSpacing;/*** 概览图上方块的垂直间距*/float overviewVerSpacing;/*** 概览图的比例*/float overviewScale = 4.8f;/*** 荧幕高度*/float screenHeight;/*** 荧幕默认宽度与座位图的比例*/float screenWidthScale = 0.5f;/*** 荧幕最小宽度*/int defaultScreenWidth;/*** 标识是否正在缩放*/boolean isScaling;float scaleX, scaleY;/*** 是否是第一次缩放*/boolean firstScale = true;/*** 最多可以选择的座位数量*/int maxSelected = Integer.MAX_VALUE;private SeatChecker seatChecker;/*** 荧幕名称*/private String screenName = "";/*** 整个概览图的宽度*/float rectW;/*** 整个概览图的高度*/float rectH;Paint headPaint;Bitmap headBitmap;/*** 是否第一次执行onDraw*/boolean isFirstDraw = true;/*** 标识是否需要绘制概览图*/boolean isDrawOverview = false;/*** 标识是否需要更新概览图*/boolean isDrawOverviewBitmap = true;int overview_checked;int overview_sold;int txt_color;int seatCheckedResID;int seatSoldResID;int seatAvailableResID;boolean isOnClick;/*** 座位已售*/private static final int SEAT_TYPE_SOLD = 1;/*** 座位已经选中*/private static final int SEAT_TYPE_SELECTED = 2;/*** 座位可选*/private static final int SEAT_TYPE_AVAILABLE = 3;/*** 座位不可用*/private static final int SEAT_TYPE_NOT_AVAILABLE = 4;private int downX, downY;private boolean pointer;/*** 顶部高度,可选,已选,已售区域的高度*/float headHeight;Paint pathPaint;RectF rectF;/*** 头部下面横线的高度*/int borderHeight = 1;Paint redBorderPaint;/*** 默认的座位图宽度,如果使用的自己的座位图片比这个尺寸大或者小,会缩放到这个大小*/private float defaultImgW = 40;/*** 默认的座位图高度*/private float defaultImgH = 34;/*** 座位图片的宽度*/private int seatWidth;/*** 座位图片的高度*/private int seatHeight;public SeatTable(Context context) {super(context);}public SeatTable(Context context, AttributeSet attrs) {super(context, attrs);init(context,attrs);}private void init(Context context,AttributeSet attrs){TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.styleable);overview_checked = typedArray.getColor(R.styleable.styleable_overview_checked, Color.parseColor("#5A9E64"));overview_sold = typedArray.getColor(R.styleable.styleable_overview_sold, Color.RED);txt_color=typedArray.getColor(R.styleable.styleable_txt_color,Color.WHITE);seatCheckedResID = typedArray.getResourceId(R.styleable.styleable_seat_checked, R.drawable.seat_gray);seatSoldResID = typedArray.getResourceId(R.styleable.styleable_overview_sold, R.drawable.sold);seatAvailableResID = typedArray.getResourceId(R.styleable.styleable_seat_available, R.drawable.seat_green);typedArray.recycle();}public SeatTable(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context,attrs);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}float xScale1 = 1;float yScale1 = 1;private void init() {spacing = (int) dip2Px(5);verSpacing = (int) dip2Px(10);defaultScreenWidth = (int) dip2Px(80);seatBitmap = BitmapFactory.decodeResource(getResources(), seatAvailableResID);float scaleX = defaultImgW / seatBitmap.getWidth();float scaleY = defaultImgH / seatBitmap.getHeight();xScale1 = scaleX;yScale1 = scaleY;seatHeight= (int) (seatBitmap.getHeight()*yScale1);seatWidth= (int) (seatBitmap.getWidth()*xScale1);checkedSeatBitmap = BitmapFactory.decodeResource(getResources(), seatCheckedResID);seatSoldBitmap = BitmapFactory.decodeResource(getResources(), seatSoldResID);seatBitmapWidth = (int) (column * seatBitmap.getWidth()*xScale1 + (column - 1) * spacing);seatBitmapHeight = (int) (row * seatBitmap.getHeight()*yScale1 + (row - 1) * verSpacing);paint.setColor(Color.RED);numberWidth = (int) dip2Px(20);screenHeight = dip2Px(20);headHeight = dip2Px(30);headPaint = new Paint();headPaint.setStyle(Paint.Style.FILL);headPaint.setTextSize(24);headPaint.setColor(Color.WHITE);headPaint.setAntiAlias(true);pathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);pathPaint.setStyle(Paint.Style.FILL);pathPaint.setColor(Color.parseColor("#e2e2e2"));redBorderPaint = new Paint();redBorderPaint.setAntiAlias(true);redBorderPaint.setColor(Color.RED);redBorderPaint.setStyle(Paint.Style.STROKE);redBorderPaint.setStrokeWidth(getResources().getDisplayMetrics().density * 1);rectF = new RectF();rectHeight = seatHeight / overviewScale;rectWidth = seatWidth / overviewScale;overviewSpacing = spacing / overviewScale;overviewVerSpacing = verSpacing / overviewScale;rectW = column * rectWidth + (column - 1) * overviewSpacing + overviewSpacing * 2;rectH = row * rectHeight + (row - 1) * overviewVerSpacing + overviewVerSpacing * 2;overviewBitmap = Bitmap.createBitmap((int) rectW, (int) rectH, Bitmap.Config.ARGB_4444);lineNumberPaint = new Paint(Paint.ANTI_ALIAS_FLAG);lineNumberPaint.setColor(bacColor);lineNumberPaint.setTextSize(getResources().getDisplayMetrics().density * 16);lineNumberTxtHeight = lineNumberPaint.measureText("4");lineNumberPaintFontMetrics = lineNumberPaint.getFontMetrics();lineNumberPaint.setTextAlign(Paint.Align.CENTER);if(lineNumbers==null){lineNumbers=new ArrayList<>();}else if(lineNumbers.size()<=0) {for (int i = 0; i < row; i++) {lineNumbers.add((i + 1) + "");}}matrix.postTranslate(numberWidth + spacing, headHeight + screenHeight + borderHeight + verSpacing);}@Overrideprotected void onDraw(Canvas canvas) {long startTime = System.currentTimeMillis();if (row <= 0 || column == 0) {return;}drawSeat(canvas);drawNumber(canvas);if (headBitmap == null) {headBitmap = drawHeadInfo();}canvas.drawBitmap(headBitmap, 0, 0, null);drawScreen(canvas);if (isDrawOverview) {long s = System.currentTimeMillis();if (isDrawOverviewBitmap) {drawOverview();}canvas.drawBitmap(overviewBitmap, 0, 0, null);drawOverview(canvas);Log.d("drawTime", "OverviewDrawTime:" + (System.currentTimeMillis() - s));}if (DBG) {long drawTime = System.currentTimeMillis() - startTime;Log.d("drawTime", "totalDrawTime:" + drawTime);}}@Overridepublic boolean onTouchEvent(MotionEvent event) {int y = (int) event.getY();int x = (int) event.getX();super.onTouchEvent(event);scaleGestureDetector.onTouchEvent(event);gestureDetector.onTouchEvent(event);int pointerCount = event.getPointerCount();if (pointerCount > 1) {pointer = true;}switch (event.getAction()) {case MotionEvent.ACTION_DOWN:pointer = false;downX = x;downY = y;isDrawOverview = true;handler.removeCallbacks(hideOverviewRunnable);invalidate();break;case MotionEvent.ACTION_MOVE:if (!isScaling && !isOnClick) {int downDX = Math.abs(x - downX);int downDY = Math.abs(y - downY);if ((downDX > 10 || downDY > 10) && !pointer) {int dx = x - lastX;int dy = y - lastY;matrix.postTranslate(dx, dy);invalidate();}}break;case MotionEvent.ACTION_UP:handler.postDelayed(hideOverviewRunnable, 1500);autoScale();int downDX = Math.abs(x - downX);int downDY = Math.abs(y - downY);if ((downDX > 10 || downDY > 10) && !pointer) {autoScroll();}break;}isOnClick = false;lastY = y;lastX = x;return true;}private Runnable hideOverviewRunnable = new Runnable() {@Overridepublic void run() {isDrawOverview = false;invalidate();}};Bitmap drawHeadInfo() {String txt = "已售";float txtY = getBaseLine(headPaint, 0, headHeight);int txtWidth = (int) headPaint.measureText(txt);float spacing = dip2Px(10);float spacing1 = dip2Px(5);float y = (headHeight - seatBitmap.getHeight()) / 2;float width = seatBitmap.getWidth() + spacing1 + txtWidth + spacing + seatSoldBitmap.getWidth() + txtWidth + spacing1 + spacing + checkedSeatBitmap.getHeight() + spacing1 + txtWidth;Bitmap bitmap = Bitmap.createBitmap(getWidth(), (int) headHeight, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);//绘制背景canvas.drawRect(0, 0, getWidth(), headHeight, headPaint);headPaint.setColor(Color.BLACK);float startX = (getWidth() - width) / 2;tempMatrix.setScale(xScale1,yScale1);tempMatrix.postTranslate(startX,(headHeight - seatHeight) / 2);canvas.drawBitmap(seatBitmap, tempMatrix, headPaint);canvas.drawText("可选", startX + seatWidth + spacing1, txtY, headPaint);float soldSeatBitmapY = startX + seatBitmap.getWidth() + spacing1 + txtWidth + spacing;tempMatrix.setScale(xScale1,yScale1);tempMatrix.postTranslate(soldSeatBitmapY,(headHeight - seatHeight) / 2);canvas.drawBitmap(seatSoldBitmap, tempMatrix, headPaint);canvas.drawText("已售", soldSeatBitmapY + seatWidth + spacing1, txtY, headPaint);float checkedSeatBitmapX = soldSeatBitmapY + seatSoldBitmap.getWidth() + spacing1 + txtWidth + spacing;tempMatrix.setScale(xScale1,yScale1);tempMatrix.postTranslate(checkedSeatBitmapX,y);canvas.drawBitmap(checkedSeatBitmap, tempMatrix, headPaint);canvas.drawText("已选", checkedSeatBitmapX + spacing1 + seatWidth, txtY, headPaint);//绘制分割线headPaint.setStrokeWidth(1);headPaint.setColor(Color.GRAY);canvas.drawLine(0, headHeight, getWidth(), headHeight, headPaint);return bitmap;}/*** 绘制中间屏幕*/void drawScreen(Canvas canvas) {pathPaint.setStyle(Paint.Style.FILL);pathPaint.setColor(Color.parseColor("#e2e2e2"));float startY = headHeight + borderHeight;float centerX = seatBitmapWidth * getMatrixScaleX() / 2 + getTranslateX();float screenWidth = seatBitmapWidth * screenWidthScale * getMatrixScaleX();if (screenWidth < defaultScreenWidth) {screenWidth = defaultScreenWidth;}Path path = new Path();path.moveTo(centerX, startY);path.lineTo(centerX - screenWidth / 2, startY);path.lineTo(centerX - screenWidth / 2 + 20, screenHeight * getMatrixScaleY() + startY);path.lineTo(centerX + screenWidth / 2 - 20, screenHeight * getMatrixScaleY() + startY);path.lineTo(centerX + screenWidth / 2, startY);canvas.drawPath(path, pathPaint);pathPaint.setColor(Color.BLACK);pathPaint.setTextSize(20 * getMatrixScaleX());canvas.drawText(screenName, centerX - pathPaint.measureText(screenName) / 2, getBaseLine(pathPaint, startY, startY + screenHeight * getMatrixScaleY()), pathPaint);}Matrix tempMatrix = new Matrix();void drawSeat(Canvas canvas) {zoom = getMatrixScaleX();long startTime = System.currentTimeMillis();float translateX = getTranslateX();float translateY = getTranslateY();float scaleX = zoom;float scaleY = zoom;for (int i = 0; i < row; i++) {float top = i * seatBitmap.getHeight() * yScale1 * scaleY + i * verSpacing * scaleY + translateY;float bottom = top + seatBitmap.getHeight() * yScale1 * scaleY;if (bottom < 0 || top > getHeight()) {continue;}for (int j = 0; j < column; j++) {float left = j * seatBitmap.getWidth() * xScale1 * scaleX + j * spacing * scaleX + translateX;float right = (left + seatBitmap.getWidth() * xScale1 * scaleY);if (right < 0 || left > getWidth()) {continue;}int seatType = getSeatType(i, j);tempMatrix.setTranslate(left, top);tempMatrix.postScale(xScale1, yScale1, left, top);tempMatrix.postScale(scaleX, scaleY, left, top);switch (seatType) {case SEAT_TYPE_AVAILABLE:canvas.drawBitmap(seatBitmap, tempMatrix, paint);break;case SEAT_TYPE_NOT_AVAILABLE:break;case SEAT_TYPE_SELECTED:canvas.drawBitmap(checkedSeatBitmap, tempMatrix, paint);drawText(canvas, i, j, top, left);break;case SEAT_TYPE_SOLD:canvas.drawBitmap(seatSoldBitmap, tempMatrix, paint);break;}}}if (DBG) {long drawTime = System.currentTimeMillis() - startTime;Log.d("drawTime", "seatDrawTime:" + drawTime);}}private int getSeatType(int row, int column) {if (isHave(getID(row, column)) >= 0) {return SEAT_TYPE_SELECTED;}if (seatChecker != null) {if (!seatChecker.isValidSeat(row, column)) {return SEAT_TYPE_NOT_AVAILABLE;} else if (seatChecker.isSold(row, column)) {return SEAT_TYPE_SOLD;}}return SEAT_TYPE_AVAILABLE;}private int getID(int row, int column) {return row * this.column + (column + 1);}/*** 绘制选中座位的行号列号** @param row* @param column*/private void drawText(Canvas canvas, int row, int column, float top, float left) {String txt = (row + 1) + "排";String txt1 = (column + 1) + "座";if(seatChecker!=null){String[] strings = seatChecker.checkedSeatTxt(row, column);if(strings!=null&&strings.length>0){if(strings.length>=2){txt=strings[0];txt1=strings[1];}else {txt=strings[0];txt1=null;}}}TextPaint txtPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);txtPaint.setColor(txt_color);txtPaint.setTypeface(Typeface.DEFAULT_BOLD);float seatHeight = this.seatHeight * getMatrixScaleX();float seatWidth = this.seatWidth * getMatrixScaleX();txtPaint.setTextSize(seatHeight / 3);//获取中间线float center = seatHeight / 2;float txtWidth = txtPaint.measureText(txt);float startX = left + seatWidth / 2 - txtWidth / 2;//只绘制一行文字if(txt1==null){canvas.drawText(txt, startX, getBaseLine(txtPaint, top, top + seatHeight), txtPaint);}else {canvas.drawText(txt, startX, getBaseLine(txtPaint, top, top + center), txtPaint);canvas.drawText(txt1, startX, getBaseLine(txtPaint, top + center, top + center + seatHeight / 2), txtPaint);}if (DBG) {Log.d("drawTest:", "top:" + top);}}int bacColor = Color.parseColor("#7e000000");/*** 绘制行号*/void drawNumber(Canvas canvas) {long startTime = System.currentTimeMillis();lineNumberPaint.setColor(bacColor);int translateY = (int) getTranslateY();float scaleY = getMatrixScaleY();rectF.top = translateY - lineNumberTxtHeight / 2;rectF.bottom = translateY + (seatBitmapHeight * scaleY) + lineNumberTxtHeight / 2;rectF.left = 0;rectF.right = numberWidth;canvas.drawRoundRect(rectF, numberWidth / 2, numberWidth / 2, lineNumberPaint);lineNumberPaint.setColor(Color.WHITE);for (int i = 0; i < row; i++) {float top = (i *seatHeight + i * verSpacing) * scaleY + translateY;float bottom = (i * seatHeight + i * verSpacing + seatHeight) * scaleY + translateY;float baseline = (bottom + top - lineNumberPaintFontMetrics.bottom - lineNumberPaintFontMetrics.top) / 2;canvas.drawText(lineNumbers.get(i), numberWidth / 2, baseline, lineNumberPaint);}if (DBG) {long drawTime = System.currentTimeMillis() - startTime;Log.d("drawTime", "drawNumberTime:" + drawTime);}}/*** 绘制概览图*/void drawOverview(Canvas canvas) {//绘制红色框int left = (int) -getTranslateX();if (left < 0) {left = 0;}left /= overviewScale;left /= getMatrixScaleX();int currentWidth = (int) (getTranslateX() + (column * seatWidth + spacing * (column - 1)) * getMatrixScaleX());if (currentWidth > getWidth()) {currentWidth = currentWidth - getWidth();} else {currentWidth = 0;}int right = (int) (rectW - currentWidth / overviewScale / getMatrixScaleX());float top = -getTranslateY() + headHeight;if (top < 0) {top = 0;}top /= overviewScale;top /= getMatrixScaleY();if (top > 0) {top += overviewVerSpacing;}int currentHeight = (int) (getTranslateY() + (row * seatHeight + verSpacing * (row - 1)) * getMatrixScaleY());if (currentHeight > getHeight()) {currentHeight = currentHeight - getHeight();} else {currentHeight = 0;}int bottom = (int) (rectH - currentHeight / overviewScale / getMatrixScaleY());canvas.drawRect(left, top, right, bottom, redBorderPaint);}Bitmap drawOverview() {isDrawOverviewBitmap = false;int bac = Color.parseColor("#7e000000");overviewPaint.setColor(bac);overviewPaint.setAntiAlias(true);overviewPaint.setStyle(Paint.Style.FILL);overviewBitmap.eraseColor(Color.TRANSPARENT);Canvas canvas = new Canvas(overviewBitmap);//绘制透明灰色背景canvas.drawRect(0, 0, rectW, rectH, overviewPaint);overviewPaint.setColor(Color.WHITE);for (int i = 0; i < row; i++) {float top = i * rectHeight + i * overviewVerSpacing + overviewVerSpacing;for (int j = 0; j < column; j++) {int seatType = getSeatType(i, j);switch (seatType) {case SEAT_TYPE_AVAILABLE:overviewPaint.setColor(Color.WHITE);break;case SEAT_TYPE_NOT_AVAILABLE:continue;case SEAT_TYPE_SELECTED:overviewPaint.setColor(overview_checked);break;case SEAT_TYPE_SOLD:overviewPaint.setColor(overview_sold);break;}float left;left = j * rectWidth + j * overviewSpacing + overviewSpacing;canvas.drawRect(left, top, left + rectWidth, top + rectHeight, overviewPaint);}}return overviewBitmap;}/*** 自动回弹* 整个大小不超过控件大小的时候:* 往左边滑动,自动回弹到行号右边* 往右边滑动,自动回弹到右边* 往上,下滑动,自动回弹到顶部* <p>* 整个大小超过控件大小的时候:* 往左侧滑动,回弹到最右边,往右侧滑回弹到最左边* 往上滑动,回弹到底部,往下滑动回弹到顶部*/private void autoScroll() {float currentSeatBitmapWidth = seatBitmapWidth * getMatrixScaleX();float currentSeatBitmapHeight = seatBitmapHeight * getMatrixScaleY();float moveYLength = 0;float moveXLength = 0;//处理左右滑动的情况if (currentSeatBitmapWidth < getWidth()) {if (getTranslateX() < 0 || getMatrixScaleX() < numberWidth + spacing) {//计算要移动的距离if (getTranslateX() < 0) {moveXLength = (-getTranslateX()) + numberWidth + spacing;} else {moveXLength = numberWidth + spacing - getTranslateX();}}} else {if (getTranslateX() < 0 && getTranslateX() + currentSeatBitmapWidth > getWidth()) {} else {//往左侧滑动if (getTranslateX() + currentSeatBitmapWidth < getWidth()) {moveXLength = getWidth() - (getTranslateX() + currentSeatBitmapWidth);} else {//右侧滑动moveXLength = -getTranslateX() + numberWidth + spacing;}}}float startYPosition = screenHeight * getMatrixScaleY() + verSpacing * getMatrixScaleY() + headHeight + borderHeight;//处理上下滑动if (currentSeatBitmapHeight+headHeight < getHeight()) {if (getTranslateY() < startYPosition) {moveYLength = startYPosition - getTranslateY();} else {moveYLength = -(getTranslateY() - (startYPosition));}} else {if (getTranslateY() < 0 && getTranslateY() + currentSeatBitmapHeight > getHeight()) {} else {//往上滑动if (getTranslateY() + currentSeatBitmapHeight < getHeight()) {moveYLength = getHeight() - (getTranslateY() + currentSeatBitmapHeight);} else {moveYLength = -(getTranslateY() - (startYPosition));}}}Point start = new Point();start.x = (int) getTranslateX();start.y = (int) getTranslateY();Point end = new Point();end.x = (int) (start.x + moveXLength);end.y = (int) (start.y + moveYLength);moveAnimate(start, end);}private void autoScale() {if (getMatrixScaleX() > 2.2) {zoomAnimate(getMatrixScaleX(), 2.0f);} else if (getMatrixScaleX() < 0.98) {zoomAnimate(getMatrixScaleX(), 1.0f);}}Handler handler = new Handler();ArrayList<Integer> selects = new ArrayList<>();public ArrayList<String> getSelectedSeat(){ArrayList<String> results=new ArrayList<>();for(int i=0;i<this.row;i++){for(int j=0;j<this.column;j++){if(isHave(getID(i,j))>=0){results.add(i+","+j);}}}return results;}private int isHave(Integer seat) {return Collections.binarySearch(selects, seat);}private void remove(int index) {selects.remove(index);}float[] m = new float[9];private float getTranslateX() {matrix.getValues(m);return m[2];}private float getTranslateY() {matrix.getValues(m);return m[5];}private float getMatrixScaleY() {matrix.getValues(m);return m[4];}private float getMatrixScaleX() {matrix.getValues(m);return m[Matrix.MSCALE_X];}private float dip2Px(float value) {return getResources().getDisplayMetrics().density * value;}private float getBaseLine(Paint p, float top, float bottom) {Paint.FontMetrics fontMetrics = p.getFontMetrics();int baseline = (int) ((bottom + top - fontMetrics.bottom - fontMetrics.top) / 2);return baseline;}private void moveAnimate(Point start, Point end) {ValueAnimator valueAnimator = ValueAnimator.ofObject(new MoveEvaluator(), start, end);valueAnimator.setInterpolator(new DecelerateInterpolator());MoveAnimation moveAnimation = new MoveAnimation();valueAnimator.addUpdateListener(moveAnimation);valueAnimator.setDuration(400);valueAnimator.start();}private void zoomAnimate(float cur, float tar) {ValueAnimator valueAnimator = ValueAnimator.ofFloat(cur, tar);valueAnimator.setInterpolator(new DecelerateInterpolator());ZoomAnimation zoomAnim = new ZoomAnimation();valueAnimator.addUpdateListener(zoomAnim);valueAnimator.addListener(zoomAnim);valueAnimator.setDuration(400);valueAnimator.start();}private float zoom;private void zoom(float zoom) {float z = zoom / getMatrixScaleX();matrix.postScale(z, z, scaleX, scaleY);invalidate();}private void move(Point p) {float x = p.x - getTranslateX();float y = p.y - getTranslateY();matrix.postTranslate(x, y);invalidate();}class MoveAnimation implements ValueAnimator.AnimatorUpdateListener {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {Point p = (Point) animation.getAnimatedValue();move(p);}}class MoveEvaluator implements TypeEvaluator {@Overridepublic Object evaluate(float fraction, Object startValue, Object endValue) {Point startPoint = (Point) startValue;Point endPoint = (Point) endValue;int x = (int) (startPoint.x + fraction * (endPoint.x - startPoint.x));int y = (int) (startPoint.y + fraction * (endPoint.y - startPoint.y));return new Point(x, y);}}class ZoomAnimation implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {zoom = (Float) animation.getAnimatedValue();zoom(zoom);if (DBG) {Log.d("zoomTest", "zoom:" + zoom);}}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationEnd(Animator animation) {}@Overridepublic void onAnimationRepeat(Animator animation) {}@Overridepublic void onAnimationStart(Animator animation) {}}public void setData(int row, int column) {this.row = row;this.column = column;init();invalidate();}ScaleGestureDetector scaleGestureDetector = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.OnScaleGestureListener() {@Overridepublic boolean onScale(ScaleGestureDetector detector) {isScaling = true;float scaleFactor = detector.getScaleFactor();if (getMatrixScaleY() * scaleFactor > 3) {scaleFactor = 3 / getMatrixScaleY();}if (firstScale) {scaleX = detector.getCurrentSpanX();scaleY = detector.getCurrentSpanY();firstScale = false;}if (getMatrixScaleY() * scaleFactor < 0.5) {scaleFactor = 0.5f / getMatrixScaleY();}matrix.postScale(scaleFactor, scaleFactor, scaleX, scaleY);invalidate();return true;}@Overridepublic boolean onScaleBegin(ScaleGestureDetector detector) {return true;}@Overridepublic void onScaleEnd(ScaleGestureDetector detector) {isScaling = false;firstScale = true;}});GestureDetector gestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {@Overridepublic boolean onSingleTapConfirmed(MotionEvent e) {isOnClick = true;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 + (j+1) * spacing) * getMatrixScaleX() + getTranslateX());int maxTemX = (int) (tempX + seatWidth * getMatrixScaleX());int tempY = (int) ((i * seatHeight + i * verSpacing) * getMatrixScaleY() + getTranslateY());int maxTempY = (int) (tempY + seatHeight * getMatrixScaleY());if (seatChecker != null && seatChecker.isValidSeat(i, j) && !seatChecker.isSold(i, j)) {if (x >= tempX && x <= maxTemX && y >= tempY && y <= maxTempY) {int id = getID(i, j);int index = isHave(id);if (index >= 0) {remove(index);if (seatChecker != null) {seatChecker.unCheck(i, j);}} else {if (selects.size() >= maxSelected) {Toast.makeText(getContext(), "最多只能选择" + maxSelected + "个", Toast.LENGTH_SHORT).show();return super.onSingleTapConfirmed(e);} else {addChooseSeat(i, j);if (seatChecker != null) {seatChecker.checked(i, j);}}}isNeedDrawSeatBitmap = true;isDrawOverviewBitmap = true;float currentScaleY = getMatrixScaleY();if (currentScaleY < 1.7) {scaleX = x;scaleY = y;zoomAnimate(currentScaleY, 1.9f);}invalidate();break;}}}}return super.onSingleTapConfirmed(e);}});private void addChooseSeat(int row, int column) {int id = getID(row, column);for (int i = 0; i < selects.size(); i++) {int item = selects.get(i);if (id < item) {selects.add(i, id);return;}}selects.add(id);}public interface SeatChecker {/*** 是否可用座位** @param row* @param column* @return*/boolean isValidSeat(int row, int column);/*** 是否已售** @param row* @param column* @return*/boolean isSold(int row, int column);void checked(int row, int column);void unCheck(int row, int column);/*** 获取选中后座位上显示的文字* @param row* @param column* @return 返回2个元素的数组,第一个元素是第一行的文字,第二个元素是第二行文字,如果只返回一个元素则会绘制到座位图的中间位置*/String[] checkedSeatTxt(int row, int column);}public void setScreenName(String screenName) {this.screenName = screenName;}public void setMaxSelected(int maxSelected) {this.maxSelected = maxSelected;}public void setSeatChecker(SeatChecker seatChecker) {this.seatChecker = seatChecker;invalidate();}private int getRowNumber(int row){int result=row;if(seatChecker==null){return -1;}for(int i=0;i<row;i++){for (int j=0;j<column;j++){if(seatChecker.isValidSeat(i,j)){break;}if(j==column-1){if(i==row){return -1;}result--;}}}return result;}private int getColumnNumber(int row,int column){int result=column;if(seatChecker==null){return -1;}for(int i=row;i<=row;i++){for (int j=0;j<column;j++){if(!seatChecker.isValidSeat(i,j)){if(j==column){return -1;}result--;}}}return result;}
}

第二步:

在values文件下写

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="styleable"><attr name="seat_checked" format="reference" /><attr name="seat_sold" format="reference" /><attr name="seat_available" format="reference" /><attr name="overview_checked" format="color" /><attr name="overview_sold" format="color" /><attr name="txt_color" format="color"/></declare-styleable><declare-styleable name="LinearGradientTextView4"><attr name="lineNumber" format="integer"></attr><attr name="showTime" format="integer"></attr><attr name="textColor" format="color"></attr><attr name="showStyle"><enum name="UNIDIRECTION" value="0"></enum><enum name="TWOWAY" value="1"></enum></attr></declare-styleable>
</resources>

第三步:

布局页面

<com.bw.movie.activity.cinema_activity.SeatTableandroid:id="@+id/mSearchView"android:layout_below="@+id/image"android:layout_width="match_parent"android:layout_height="match_parent"/>

第四步:

我这是在Activity中写的

找控件

seatTableView = (SeatTable)findViewById(R.id.mSearchView);
seatTableView.setScreenName("8号厅荧幕");//设置屏幕名称
seatTableView.setMaxSelected(3);//设置最多选中seatTableView.setSeatChecker(new SeatTable.SeatChecker() {@Overridepublic boolean isValidSeat(int row, int column) {if(column==2) {return false;}return true;}@Overridepublic boolean isSold(int row, int column) {if(row==6&&column==6){return true;}return false;}@Overridepublic void checked(int row, int column) {}@Overridepublic void unCheck(int row, int column) {}@Overridepublic String[] checkedSeatTxt(int row, int column) {return null;}});
seatTableView.setData(10,15);

Android影院选座相关推荐

  1. jQuery实现影院选座订座效果

    jQuery实现影院选座订座效果 效果如下: 代码如下: <!DOCTYPE html> <html><head><meta charset="ut ...

  2. 【影院选座功能模板】vue实现选座功能,点击切换图片,获取座位信息

    前言 最近突然看到这个功能了,就想着研究一下如何写, 然后在网上看了一些帖子,总结了一下, 这里套用了一个别人的数据结构,这个感觉毕竟好用. 然后写一个简单的模板放在这,以后可能会再这个基础上修改或者 ...

  3. 微信小程序影院选座界面前后端

    选座界面 使用了组件开发,在seat页面里引入seatList组件.因为不想再去看怎么从组件中获取数据,因此这整个页面就是一个组件... 本文前端部分参考于:微信小程序组件开发--可视化电影选座 - ...

  4. html影院选座模板,jQuery在线选座(影院版)

    jquery.seat-charts是一款适合电影票.高铁票的在线选座插件,支持自定义样式,支持设置座位状态,并且支持键盘控制座位. 查看演示 下载资源: 2215 次 下载资源 下载积分: 106 ...

  5. php 影院选座js代码,在react中用canvas做一个电影院选座功能

    又到了每日分享了.这次分享的是:在react中用canvas做一个电影院选座功能. 前言:项目采用create-react-app脚手架,就是做了一个效果所以只有一个页面但是也用了react-rout ...

  6. Java_167_Thread_线程安全synchronized_模拟选座_List「Integer」

    模拟影院选座 package TCPUDPThread;import java.util.ArrayList; import java.util.List;/*** 快乐影院* * @author p ...

  7. 自定义View实战:影院在线选座

    不知道周末有没有小伙伴使用在线选座app看电影?今天来自 起风的清晨 的投稿,将高度还原淘票票APP,大家可以自己评判一下还原度噢~~ 起风的清晨 的博客地址: http://blog.csdn.ne ...

  8. android studio电影院选座,8排电影院选座最佳位置

    8排电影院选座最佳位置在哪里呢?8排电影院属于小影厅,小影厅银幕宽度在10米以下,座位100以内,座位排数通常拥有8-14排,小影厅整体空间小,选座时要选中间稍靠后一些的位置.由于整体排数少,因此选即 ...

  9. jQuery在线选座订座(影院篇)

    jQuery在线选座订座(影院篇) 原文:jQuery在线选座订座(影院篇) 我们在线购票时(如电影票.车票等)可以自己选座.开发者会在页面上列出座次席位,用户可以一目了然的看到可以选择的座位及支付. ...

  10. php 在线选座,基于jquery实现在线选座订座之影院篇

    先给大家展示效果图(支持源码下载哦): 我们在线购票时(如电影票.车票等)可以自己选座.开发者会在页面上列出座次席位,用户可以一目了然的看到可以选择的座位及支付.本文以电影院购票为例,为您展示如何选座 ...

最新文章

  1. java中的排序算法——归并排序
  2. PAT甲级题目翻译+答案 AcWing(动态规划)
  3. Google Megastore介绍
  4. css 样式(checkbox开关、css按钮)
  5. IT程序员在北京可以选择哪些国企、央企以及研究所?
  6. vue 开发中element-ui库的switch开关绑定number类型数据不成功问题 解决方法
  7. 虚拟机登录/系统管理等命令
  8. svn 把本地的项目,上传到服务器端
  9. document.frames()与document.frames[]的区别
  10. 用电池给树莓派供电_3个用于便携式项目的树莓派电池组介绍
  11. 采访:蔡学镛谈复杂事务处理(CEP)
  12. flashfxp使用图文教程,flashfxp使用图文教程简单介绍
  13. 脉冲神经网络(Spiking Neural Network,SNN)概述
  14. Unet分割直肠肿瘤图像
  15. 基于STM32开源项目:球上自平衡机器人
  16. 计算机网络中国科学家,“留光” 1 小时!中国科学家刷新世界纪录
  17. 人工智能作业——python实现洗衣机模糊推理系统实验
  18. 奥的斯服务器显示chc,奥的斯服务器中文说明.docx
  19. Rust能力养成之(12)用Cargo进行项目管理:实操项目imgtool
  20. 雪淇MM最经典的10句话

热门文章

  1. Hadoop完全分布式配置
  2. vs2019中git提交代码的步骤
  3. Linux 压缩文件 排除指定的目录和 指定的后缀,超实用
  4. windows磁盘备份还原
  5. 光遇自动弹琴脚本代码_光遇自动弹琴脚本
  6. 软考初级程序员---题目(四)
  7. 中国大学Mooc平台,自动下载pdf文档
  8. 文本检测与识别(OCR)资源汇总(持续更新)
  9. 软件工程专业英语专用名词翻译
  10. 软件工程大一至大四课程