最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android打造炫酷的電影票在線選座app在線選座功能

 更新時間:2016年09月04日 10:09:39   作者:qifengdeqingchen  
這篇文章主要介紹了Android打造炫酷的電影票在線選座app在線選座功能的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下

不知道大家有沒有用過,淘寶電影客戶端(淘票票)買過電影票,縱觀各類在線選座app的在線選座功能 淘寶在線選座功能用戶體驗最好,用起來最順手,夸張點說已經(jīng)到了爐火純青的地步,下面我們看一下效果:

這里寫圖片描述

效果分析:

整個控件分成幾個部分,座位圖區(qū)域、座位縮略圖區(qū)域、行號區(qū)域、屏幕區(qū)域

1、座位圖可以自由的移動縮放,放大縮小移動后會自動回彈到合適的位置,選中座位會自動放大到合適比例。

2、行號部分跟著座位圖縮放以及上下移動,屏幕區(qū)域跟著座位圖左右移動縮放。

3、當(dāng)手指按下的時候會出現(xiàn)縮略圖,縮略圖上有個紅色的方框表示,當(dāng)前能看到的區(qū)域,并且跟隨縮略圖的移動。

涉及到的知識點:

view的繪制原理、事件分發(fā)機制這些就不說了,這些是基礎(chǔ),這里并不打算介紹,網(wǎng)上有非常多的這方面的資料。

1、矩陣Matrix使用,通過Matrix來進(jìn)行移動、縮放

2、彈性移動、彈性縮放。

3、手勢監(jiān)聽的使用通過GestureDetector、ScaleGestureDetector來獲得縮放比例幅度。

編碼實現(xiàn)

通過以下幾個核心部分來介紹,其他部分都是類似的思路實現(xiàn)

1、繪制座位圖

2、座位圖的縮放和移動

3、座位圖自動回彈、自動縮放

4、縮略圖部分的繪制實現(xiàn)

至于其他部分比如影院熒幕,左側(cè)的行號部分思路跟座位圖的實現(xiàn)思路是一致的。

1、繪制座位圖

座位圖實際上就是個二維矩陣,有行數(shù)和列數(shù),我們只需要根據(jù)行數(shù)和列數(shù)加上一定的間距繪制即可。

void drawSeat() {
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
int left = j * seatBitmap.getWidth() + j * spacing;
int top = i * seatBitmap.getHeight() + i * verSpacing;
int seatType = getSeatType(i, j);
switch (seatType) {
case SEAT_TYPE_AVAILABLE:
seatCanvas.drawBitmap(seatBitmap, left, top, paint);
break;
case SEAT_TYPE_NOT_AVAILABLE:
break;
case SEAT_TYPE_SELECTED:
seatCanvas.drawBitmap(checkedSeatBitmap, left, top, paint);
break;
case SEAT_TYPE_SOLD:
seatCanvas.drawBitmap(seatSoldBitmap, left, top, paint);
break;
}
}
}
isNeedDrawSeatBitmap = false;
}

getSeatType()方法是用來判斷當(dāng)前的座位是否可用,是否已經(jīng)賣出去,是否已經(jīng)選中,根據(jù)這些狀態(tài)繪制不同的座位圖。

2、座位圖的縮放和移動

移動縮放功能使用 Matirx來實現(xiàn),Matrix在android中可以用來對圖片進(jìn)行縮放、移動、旋轉(zhuǎn)等變換。
matrix本身是一個3*3的矩陣,矩陣中的每一個值都代表一個變換屬性,如下

MSCALE_X MSKEW_X MTRANS_X 
MSKEW_Y MSCALE_Y MTRANS_Y 
MPERSP_0 MPERSP_1 MPERSP_2

實際上就是一個有9個元素的數(shù)組

float[] value=new float[9]; 

通過 matrix.getValues(value);可以獲得具體的值。

value[0]表示的是縮放的x值

value[1]表示的是斜切的x值

value[2] 表示x軸上平移的值

value[3]表示的是斜切的y值

value[4]表示的y軸上的縮放比例

value[5]表示的是y軸上的平移的值

Matrix類有一些方法可以對這些值進(jìn)行改變

setScale(float sx, float sy, float px, float py) :設(shè)置x軸和y周上的縮放比例,px,py表示縮放的中心點。

setTranslate(float dx, float dy) :設(shè)置x軸和y周上的偏移量。

與之對應(yīng)的還有這么兩個方法:

postScale(float sx, float sy, float px, float py) 
postTranslate(float dx, float dy) 

那么post跟set有什么區(qū)別呢,簡單理解就是set直接,把之前的值給覆蓋了,而post是在之前的值的基礎(chǔ)上進(jìn)行變換。比如現(xiàn)在你已經(jīng)向左移動了10個像素,這時候你用setTranslate(5,5)這個時候直接變成了移動5個像素了,而用post就是在10的基礎(chǔ)上在移動5個像素就變成15了。

以上是Matrix的使用方法,Canvas對象有個drawBitmap方法可以接收一個matrix,這樣就可以在繪圖的時候使用matrix進(jìn)行變換了。

座位圖平移縮放的實現(xiàn)思路:

要做兩件事情來實現(xiàn)座位圖的縮放移動

1、獲取平移的值和放大縮小的比例

重寫onTouchEvent方法來計算獲取移動的x值和y值

使用ScaleGestureDetector這個類來幫我們獲取放大縮小的比例,使用非常簡單,創(chuàng)建一個ScaleGestureDetector的對象,然后在onTouchEvent方法了調(diào)用一下ScaleGestureDetector.onTouchEvent(event);即可

2、根據(jù)獲取到的值對座位圖進(jìn)行平移和縮放

獲取到了平移的值和縮放的比例后,使用matrix.postScale(x,y)和matrix.postTrans(x,y)進(jìn)行對應(yīng)的變換即可,變換完了調(diào)用view的invalidate方法讓view重新繪制matrix即可生效。

下面只列出了核心代碼,省掉了一些邏輯,完整代碼請到github中查看。

ScaleGestureDetector scaleGestureDetector = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.OnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactor = detector.getScaleFactor();
matrix.postScale(scaleFactor, scaleFactor, scaleX, scaleY);
invalidate();
return true;
}
});

onTouchEvent處理邏輯

@Override
public boolean onTouchEvent(MotionEvent event) {
int y = (int) event.getY();
int x = (int) event.getX();
scaleGestureDetector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = x;
downY = y; 
break;
case MotionEvent.ACTION_MOVE:
int downDX = Math.abs(x - downX);
int downDY = Math.abs(y - downY);
if (downDX > 10 || downDY > 10) {
int dx = x - lastX;
int dy = y - lastY;
matrix.postTranslate(dx, dy);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
....
break;
}
lastY = y;
lastX = x;
return true;
}

onDraw的時候

@Override
protected void onDraw(Canvas canvas) {
.....
canvas.drawBitmap(seat, matrix, paint);
.....
}

3、座位圖的自動回彈、自動縮放效果的實現(xiàn)

為什么要自動回彈呢,因為你操作的時候有可能把座位圖移到屏幕外,縮放的時候把圖縮放的比較小,或者比較大,這個時候程序通過計算給你自動的移動到一個比較合適的位置,比較合適的縮放大小。這樣就有著不錯的使用體驗。

自動回彈實現(xiàn)的思路:

當(dāng)我們手指屏幕上移動然后抬起的時候會觸發(fā)MotionEvent.ACTION_UP事件,這個時候我們可以通過matrix對象來獲取當(dāng)前的移動的位置,如果當(dāng)前移動的值不符合我們的規(guī)則,我們就將座位圖按照規(guī)則移動到指定位置。

移動規(guī)則如下(參考的淘票票客戶端的移動邏輯)

座位圖整個大小不超過控件大小的時候:

往左邊滑動,自動回彈到行號右邊

往右邊滑動,自動回彈到右邊

往上,下滑動,自動回彈到頂部

座位圖整個大小超過控件大小的時候:

往左側(cè)滑動,回彈到最右邊,往右側(cè)滑回彈到最左邊

往上滑動,回彈到底部,往下滑動回彈到頂部

以上的移動規(guī)則的實現(xiàn)大家可以查看具體源碼中的autoScroll()方法的實現(xiàn),這里就不貼出來了。

移動和縮放涉及到一個彈性移動和縮放的問題,所謂彈性移動就是有動畫效果的移動。因為如果你當(dāng)前在100,100 這個位置,你需要移動到800,100這個位置,如果你直接移動到800這個位置,而不是通過,先移動到110,在移動到120。。。一直到800這樣一段一段的移動。那么移動效果將是非常僵硬的,刷的閃過去的感覺,效果非常不好。

彈性移動的實現(xiàn)思路就是:

比如要從100,100 移動到800,100這個位置,很明顯 x軸要移動700個像素。那么把這700個像素的移動我們分成10次移動來實現(xiàn),每次移動700/10=70個像素,兩次移動之間間隔50毫秒,就跟幀動畫似的,這樣就會有一個彈性的動畫效果。

通過handler來實現(xiàn)代碼如下:

int FRAME_COUNT = 10;
int time = 15;
int count;
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if (count < FRAME_COUNT) {
count++;
MoveInfo moveInfo = (MoveInfo) msg.obj;
float moveXLength = moveInfo.moveXLength;
float moveYLength = moveInfo.moveYLength;
float xValue = moveXLength / FRAME_COUNT;
float yValue = moveYLength / FRAME_COUNT;
matrix.postTranslate(xValue, yValue);
invalidate();
Message message = Message.obtain();
message.obj = msg.obj;
//循環(huán)調(diào)用
handler.sendMessageDelayed(message, time);
} else {
count = 0;
}
return true;
}

彈性縮放的原理跟彈性移動的原理一致

4、縮略圖部分的繪制實現(xiàn)

縮略圖是座位圖的縮小版,縮略圖的寬高和座位圖的寬高有一定比例,比如五分之一。當(dāng)然這是可以根據(jù)效果來調(diào)整的。之所以必須是座位圖的一定比例,是因為縮略圖上有一個動態(tài)的紅色方框表示當(dāng)前可見的座位區(qū)域,這個紅色方框是需要根據(jù)座位圖的移動而移動的。比例確定后,就這可以根據(jù)座位圖的移動來移動紅色方框。舉個例子來說-如果當(dāng)前座位圖向上移動了100個像素,那么縮略圖中對應(yīng)的紅色方框部分向下移動 100/4=250個像素即可。

繪制概覽圖代碼:

Bitmap drawOverview() {
//計算概覽圖上代表座位的正方形寬度、高度 
//規(guī)則 :座位圖上座位的寬度/縮放比例
float rectSize = seatBitmap.getHeight() / overviewScale;
//計算概覽圖的寬度和高度 
rectW = column * rectWidth + (column - 1) * overviewSpacing + overviewSpacing * 2;
rectH = row * rectSize + (row - 1) * overviewVerSpacing + overviewVerSpacing * 2;
Canvas canvas = new Canvas(overviewBitmap);
//繪制透明灰色背景
canvas.drawRect(0, 0, rectW, rectH, paint);
paint.setColor(Color.WHITE);
//循環(huán)繪制
for (int i = 0; i < row; i++) {
float top = i * rectSize + i * overviewVerSpacing + overviewVerSpacing;
for (int j = 0; j < column; j++) {
//獲取座位是什么狀態(tài) 已經(jīng)售出、未選中、已經(jīng)選中
int seatType = getSeatType(i, j);
switch (seatType) {
case SEAT_TYPE_AVAILABLE:
paint.setColor(Color.WHITE);
break;
case SEAT_TYPE_NOT_AVAILABLE:
continue;
case SEAT_TYPE_SELECTED:
paint.setColor(overview_checked);
break;
case SEAT_TYPE_SOLD:
paint.setColor(overview_sold);
break;
}
float left;
left = j * rectWidth + j * overviewSpacing + overviewSpacing;
canvas.drawRect(left, top, left + rectWidth, top + rectSize, paint);
}
}
return overviewBitmap;
}

繪制概覽圖上的紅色方框

/**
* 繪制概覽圖
*/
void drawOverviewBorder(Canvas canvas) {
//繪制紅色框
int left = (int) -getTranslateX();//獲取當(dāng)前座位圖x軸上的平移位置
if (left < 0) {
left = 0;
}
left /= overviewScale; //overviewScale 表示概覽圖占座位圖的比例
left /= getMatrixScaleX();//getMatrixScaleX() 獲取當(dāng)前座位圖的縮放比例
//判斷當(dāng)前座位圖的寬度是否超出 整個控件的寬度,如果超出了,那么超出的部分就看不見。表示當(dāng)前能看到的位置的紅色方框就不能把超出的部分框進(jìn)來。
int currentWidth = (int) (getTranslateX() + (column * seatBitmap.getWidth() + 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;
}
//判斷當(dāng)前座位圖的寬度是否超出 整個控件的高度,如果超出了,那么超出的部分就看不見。表示當(dāng)前能看到的位置的紅色方框就不能把超出的部分框進(jìn)來。
int currentHeight = (int) (getTranslateY() + (row * seatBitmap.getHeight() + 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);
}

控件性能優(yōu)化

千辛萬苦終于把控件做出來了,結(jié)果一運行卡的不要不要的。特別是行數(shù)列數(shù)一多,卡頓的懵逼了。這個時候呢我們要對性能進(jìn)行優(yōu)化,總結(jié)下來主要從以下幾個方面:

1、避免在onDraw中創(chuàng)建對象,分配內(nèi)存,把paint對象的創(chuàng)建放在初始化函數(shù)里面。這一步其實非常重要因為我們使用canvas繪圖的時候需要paint對象,往往不同的地方需要不同paint,這樣一來,創(chuàng)建的paint對象就比較多了,在加上onDraw方法可能會執(zhí)行多次。頻繁的創(chuàng)建對象會造成gc,導(dǎo)致卡頓。當(dāng)然了不止是paint對象,其他的對象創(chuàng)建也要能少則少。

2、避免不必要的繪制邏輯,在需要的時候才繪制。這個需要我們根據(jù)控件的繪制邏輯來進(jìn)行調(diào)整,同樣也是非常重要。

3、總的原則就是想盡一切辦法把onDraw方法的執(zhí)行控制在16ms以內(nèi),就不會卡了。

最后看看我們實現(xiàn)的效果

這里寫圖片描述

源碼地址:

github地址

以上所述是小編給大家介紹的Android打造炫酷的電影票在線選座app在線選座功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Android自定義控件之翻轉(zhuǎn)按鈕的示例代碼

    Android自定義控件之翻轉(zhuǎn)按鈕的示例代碼

    本篇文章主要介紹了Android自定義控件之翻轉(zhuǎn)按鈕的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • 詳解Android中Notification通知提醒

    詳解Android中Notification通知提醒

    這篇文章主要為大家介紹了Android中Notification通知提醒,本文演示了普通的通知和自定義視圖通知
    2016-01-01
  • Android11文件管理權(quán)限申請詳細(xì)介紹

    Android11文件管理權(quán)限申請詳細(xì)介紹

    大家好,本篇文章主要講的是Android11文件管理權(quán)限申請詳細(xì)介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • Flutter 構(gòu)建一個常用的頁面框架

    Flutter 構(gòu)建一個常用的頁面框架

    大多數(shù) App 中都會有底部導(dǎo)航欄,通過底部導(dǎo)航欄切換實現(xiàn)不同頁面之間的切換。在Flutter 中提供了 BottomNavigationBar組件實現(xiàn)底部導(dǎo)航。本篇介紹通過 BottomNavigationBar和 IndexedStack構(gòu)建最為常見的 App 頁面框架。
    2021-05-05
  • PopupWindow?RecyclerView實現(xiàn)下拉選擇Spinner示例解析

    PopupWindow?RecyclerView實現(xiàn)下拉選擇Spinner示例解析

    這篇文章主要介紹了PopupWindow?RecyclerView實現(xiàn)下拉選擇Spinner示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 詳解Flutter如何讀寫文本文件

    詳解Flutter如何讀寫文本文件

    文本文件(具有 .txt擴展名)廣泛用于持久存儲信息,從數(shù)字?jǐn)?shù)據(jù)到長文本。本文主要為大家介紹了2個使用此文件類型的Flutter應(yīng)用程序示例,感興趣的可以了解一下
    2022-04-04
  • Android實現(xiàn)自動填充短信驗證碼功能

    Android實現(xiàn)自動填充短信驗證碼功能

    這篇文章主要為大家詳細(xì)介紹了Android實現(xiàn)自動填充短信驗證碼功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Android 自定義TextView實現(xiàn)文本內(nèi)容自動調(diào)整字體大小

    Android 自定義TextView實現(xiàn)文本內(nèi)容自動調(diào)整字體大小

    本文主要介紹了Android 自定義TextView實現(xiàn)文本內(nèi)容自動調(diào)整字體大小以適應(yīng)TextView的大小的方法。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • Android自定義View實現(xiàn)QQ消息氣泡

    Android自定義View實現(xiàn)QQ消息氣泡

    這篇文章主要為大家詳細(xì)介紹了Android自定義View實現(xiàn)QQ消息氣泡,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • android ndk程序獲取外置SD沙盒目錄的方法講解

    android ndk程序獲取外置SD沙盒目錄的方法講解

    今天小編就為大家分享一篇android ndk程序獲取外置SD沙盒目錄的方法講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08

最新評論

武邑县| 宁陕县| 彭山县| 隆尧县| 牡丹江市| 尚义县| 罗平县| 梨树县| 个旧市| 开原市| 淮阳县| 渭南市| 怀来县| 峡江县| 江口县| 孟村| 沂南县| 博爱县| 梁平县| 榆林市| 金堂县| 临沭县| 武宁县| 抚州市| 辽阳县| 大洼县| 合作市| 旬阳县| 郸城县| 万荣县| 乐亭县| 洛南县| 安远县| 扎赉特旗| 灵川县| 蕲春县| 万年县| 凌源市| 小金县| 常山县| 广灵县|