Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
頭條創(chuàng)作挑戰(zhàn)賽#
大家好,我是汪小成。最近在學(xué)習(xí)Canvas。這篇文章是我學(xué)習(xí)Canvas圖片操作時(shí)記的筆記,歡迎大家審閱。
本篇文章的示例采用下圖進(jìn)行圖片操作演示。
圖片原始尺寸為:640px * 640px。
在Canvas中,我們使用drawImage()方法繪制圖片。drawImage()方法有如下3種調(diào)用方式:
語(yǔ)法:
ctx.drawImage(image, dx, dy);
說(shuō)明:
示例源碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>X軸方向上的緩動(dòng)動(dòng)畫(huà)</title>
<script type="text/javascript" src="ball.js"></script>
</head>
<body>
<canvas
id="canvas"
width="800"
height="800"
style="border: 1px dashed #333333"
></canvas>
<script>
window.onload = function () {
// 1、獲取 Canvas 對(duì)象
var canvas = document.getElementById("canvas");
// 2、獲取上下文環(huán)境對(duì)象
var ctx = canvas.getContext("2d");
// 3、開(kāi)始繪制圖形
var image = new Image();
image.src = "flower-20221202.png";
image.onload = function () {
ctx.drawImage(image, 0, 0);
};
};
</script>
</body>
</html>
效果圖:
說(shuō)明:
本示例中,我們通過(guò)JS創(chuàng)建了一個(gè)Image對(duì)象,然后通過(guò)設(shè)置該對(duì)象的src屬性指定了圖片的路徑。最后,我們?yōu)镮mage對(duì)象添加了onload事件監(jiān)聽(tīng),只有當(dāng)圖片加載完成后再使用drawImage()方法將圖片繪制在Canvas上。
注意:只有當(dāng)圖片完全加載后才能將圖片繪制到Canvas上。如果圖片還未加載完成就調(diào)用了drawImage()方法進(jìn)行圖片繪制操作的話,Canvas將不會(huì)顯示任何圖片。
示例源碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>圖片操作簡(jiǎn)單示例</title>
</head>
<body>
<canvas
id="canvas"
width="800"
height="800"
style="border: 1px dashed #333333"
></canvas>
<img src="flower-20221202.png" id="pic" style="display: none" />
<script>
window.onload = function () {
// 1、獲取 Canvas 對(duì)象
var canvas = document.getElementById("canvas");
// 2、獲取上下文環(huán)境對(duì)象
var ctx = canvas.getContext("2d");
// 3、開(kāi)始繪制圖形
var image = document.getElementById("pic");
ctx.drawImage(image, 0, 0);
};
</script>
</body>
</html>
說(shuō)明:
本示例中的圖片來(lái)自于HTML的img元素。這種方式的優(yōu)點(diǎn)在于在JS執(zhí)行時(shí)圖片已經(jīng)加載完成,不需要使用`image.onload = function () {}'。
語(yǔ)法:
ctx.drawImage(image, dx, dy, dw, dh);
說(shuō)明:
參數(shù)image、dx、dy跟drawImage(image, dx, dy)參數(shù)含義一樣。
參數(shù)dw為圖片寬度;參數(shù)dh為圖片高度。
通過(guò)這種方式繪制圖片可以先將圖片進(jìn)行縮放,然后再繪制到Canvas中。
示例源碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>圖片操作簡(jiǎn)單示例</title>
</head>
<body>
<canvas
id="canvas"
width="400"
height="400"
style="border: 1px dashed #333333"
></canvas>
<img src="flower-20221202.png" id="pic" style="display: none" />
<script>
window.onload = function () {
// 1、獲取 Canvas 對(duì)象
var canvas = document.getElementById("canvas");
// 2、獲取上下文環(huán)境對(duì)象
var ctx = canvas.getContext("2d");
// 3、開(kāi)始繪制圖形
var image = document.getElementById("pic");
ctx.drawImage(image, 0, 0, 320, 320);
};
</script>
</body>
</html>
效果圖:
說(shuō)明:
可以看到,圖片原始大小為640px * 640px,我們使用drawImage(image, dx, dy, dw, dh)將圖片的尺寸縮放到320px * 320px,然后再繪制到Canvas上。
語(yǔ)法:
ctx.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
說(shuō)明:
參數(shù)image、dx、dy、dw、dh表示目標(biāo)圖的橫坐標(biāo)、縱坐標(biāo)、寬度、高度。
參數(shù)sx、sy、sw、sh表示源圖需要截取的范圍。sx表示被截取部分的橫坐標(biāo),sy表示被截取部分的縱坐標(biāo),sw表示被截取部分的寬度,sh表示被截取部分的高度。
示例源碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>裁減圖片示例</title>
</head>
<body>
<canvas
id="canvas"
width="800"
height="800"
style="border: 1px dashed #333333"
></canvas>
<img src="flower-20221202.png" id="pic" style="display: none" />
<script>
window.onload = function () {
// 1、獲取 Canvas 對(duì)象
var canvas = document.getElementById("canvas");
// 2、獲取上下文環(huán)境對(duì)象
var ctx = canvas.getContext("2d");
// 3、開(kāi)始繪制圖形
var image = document.getElementById("pic");
ctx.drawImage(image, 200, 200, 300, 300, 0, 0, 300, 300);
};
</script>
<style>
* {
margin: 0;
padding: 0;
}
body {
display: flex;
background: black;
align-items: center;
justify-content: center;
}
</style>
</body>
</html>
效果圖:
說(shuō)明:
圖片裁剪說(shuō)明如下圖:
我們將左側(cè)圖片中紅色框中的部分繪制到了Canvas (0, 0)位置處。
在Canvas中,我們使用createPattern()方法定義圖片的平鋪方式。
語(yǔ)法:
var pattern = ctx.createPattern(image, type);
ctx.fillStyle = pattern;
ctx.fillRect();
示例:
參數(shù)image表示被平鋪的圖片。
參數(shù)type表示平鋪的方式,type屬性取值如下表:
屬性值 | 說(shuō)明 |
repeat | 默認(rèn)值,在水平方向和垂直方向同時(shí)平鋪 |
repeat-x | 在水平方向平鋪 |
repeat-y | 在垂直方向同時(shí)平鋪 |
no-repeat | 只顯示一次,不平鋪 |
示例源碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>圖片操作簡(jiǎn)單示例</title>
</head>
<body>
<canvas
id="canvas"
width="400"
height="400"
style="border: 1px dashed #333333"
></canvas>
<img src="vip.svg" id="pic" style="display: none;" />
<script>
window.onload = function () {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var image = document.getElementById("pic");
var pattern = ctx.createPattern(image, 'repeat-x');
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, 400, 400);
};
</script>
</body>
</html>
效果圖:
以Canvas中,我們使用clip()方法切割圖片。
語(yǔ)法:
ctx.clip();
說(shuō)明:
使用clip()方法切割圖片的步驟:
(1) 繪制基本圖形; (2) 使用clip()方法; (3) 繪制圖片。
示例源碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>圖片操作簡(jiǎn)單示例</title>
</head>
<body>
<canvas
id="canvas"
width="800"
height="800"
style="border: 1px dashed #333333"
></canvas>
<img src="flower-20221202.png" id="pic" style="display: none" />
<script>
window.onload = function () {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// 第一步:繪制基本圖片
ctx.beginPath();
ctx.arc(400, 400, 320, 0, Math.PI, true);
ctx.closePath();
ctx.stroke();
// 第二步:使用clip()方法
ctx.clip();
// 第三步,繪制圖片
var image = document.getElementById("pic");
ctx.drawImage(image, 80, 80, 640, 640);
};
</script>
</body>
</html>
效果圖:
說(shuō)明:
我們使用半圓作為切割區(qū)域切割了圖片。
在,終于有可能在瀏覽器中運(yùn)行人臉識(shí)別了!通過(guò)本文,我將介紹face-api,它是一個(gè)構(gòu)建在tensorflow.js core的JavaScript模塊,它實(shí)現(xiàn)了人臉檢測(cè)、人臉識(shí)別和人臉地標(biāo)檢測(cè)三種類(lèi)型的CNN。
我們首先研究一個(gè)簡(jiǎn)單的代碼示例,以用幾行代碼立即開(kāi)始使用該包。
第一個(gè)face-recognition.js,現(xiàn)在又是一個(gè)包?
如果你讀過(guò)關(guān)于人臉識(shí)別與其他的NodeJS文章:(https://medium.com/@muehler.v/node-js-face-recognition-js-simple-and-robust-face-recognition-using-deep-learning-ea5ba8e852),你可能知道,不久前,我組裝了一個(gè)類(lèi)似的包(face-recognition.js)。
起初,我沒(méi)有想到在javascript社區(qū)中對(duì)臉部識(shí)別軟件包的需求如此之高。對(duì)于很多人來(lái)說(shuō),face-recognition.js似乎是一個(gè)不錯(cuò)的免費(fèi)使用且開(kāi)源的替代付費(fèi)服務(wù)的人臉識(shí)別服務(wù),就像微軟或亞馬遜提供的一樣。其中很多人問(wèn),是否可以在瀏覽器中完全運(yùn)行完整的人臉識(shí)別管道。
在這里,我應(yīng)該感謝tensorflow.js!我設(shè)法使用tfjs-core實(shí)現(xiàn)了部分類(lèi)似的工具,這使你可以在瀏覽器中獲得與face-recognition.js幾乎相同的結(jié)果!最好的部分是,不需要設(shè)置任何外部依賴(lài)關(guān)系,可以直接使用。并且,它是GPU加速的,在WebGL上運(yùn)行操作。
這使我相信,JavaScript社區(qū)需要這樣的瀏覽器包!你可以用這個(gè)來(lái)構(gòu)建自己的各種各樣的應(yīng)用程序。;)
如何用深度學(xué)習(xí)解決人臉識(shí)別問(wèn)題
如果你希望盡快開(kāi)始,也可以直接去編碼。但想要更好地理解face-api.js中用于實(shí)現(xiàn)人臉識(shí)別的方法,我強(qiáng)烈建議你看一看,這里有很多我經(jīng)常被問(wèn)到的問(wèn)題。
簡(jiǎn)單地說(shuō),我們真正想要實(shí)現(xiàn)的是,識(shí)別一個(gè)人的面部圖像(input image)。我們這樣做的方式是為每個(gè)我們想要識(shí)別的人提供一個(gè)(或多個(gè))圖像,并標(biāo)注人名(reference data)。現(xiàn)在我們將它們進(jìn)行比較,并找到最相似的參考圖像。如果兩張圖片足夠相似,我們輸出該人的姓名,否則我們輸出“unknown”。
聽(tīng)起來(lái)不錯(cuò)吧!然而,還是存在兩個(gè)問(wèn)題。首先,如果我們有一張顯示多個(gè)人的圖片,我們想要識(shí)別所有的人,該怎么辦?其次,我們需要能夠獲得這種類(lèi)型的兩張人臉圖像的相似性度量,以便比較它們......
人臉檢測(cè)
第一個(gè)問(wèn)題的答案是人臉檢測(cè)。簡(jiǎn)而言之,我們將首先找到輸入圖像中的所有人臉。對(duì)于人臉檢測(cè),face-api.js實(shí)現(xiàn)了SSD(Single Shot Multibox Detector),它基本上是基于MobileNetV1的CNN,只是在網(wǎng)絡(luò)頂部疊加了一些額外的盒預(yù)測(cè)層。
網(wǎng)絡(luò)返回每個(gè)人臉的邊界框及其相應(yīng)的分?jǐn)?shù),即每個(gè)邊界框顯示一個(gè)人臉的可能性。分?jǐn)?shù)用于過(guò)濾邊界框,因?yàn)閳D像中可能根本不包含任何人臉。請(qǐng)注意,即使只有一個(gè)人檢索邊界框,也應(yīng)執(zhí)行人臉檢測(cè)。
人臉標(biāo)志檢測(cè)和人臉對(duì)齊
第一個(gè)問(wèn)題解決了!但是,我們希望對(duì)齊邊界框,這樣我們就可以在每個(gè)框的人臉中心提取出圖像,然后將它們傳遞給人臉識(shí)別網(wǎng)絡(luò),這會(huì)使人臉識(shí)別更加準(zhǔn)確!
為此,face-api.js實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的CNN,它返回給定人臉圖像的68個(gè)點(diǎn)的人臉標(biāo)志:
從地標(biāo)位置,邊界框可以準(zhǔn)確的包圍人臉。在下圖,你可以看到人臉檢測(cè)的結(jié)果(左)與對(duì)齊的人臉圖像(右)的比較:
人臉識(shí)別
現(xiàn)在我們可以將提取并對(duì)齊的人臉圖像提供給人臉識(shí)別網(wǎng)絡(luò),這個(gè)網(wǎng)絡(luò)基于類(lèi)似ResNet-34的架構(gòu)并且基本上與dlib中實(shí)現(xiàn)的架構(gòu)相對(duì)應(yīng)。該網(wǎng)絡(luò)已經(jīng)被訓(xùn)練學(xué)習(xí)將人臉的特征映射到人臉描述符(descriptor ,具有128個(gè)值的特征矢量),這通常也被稱(chēng)為人臉嵌入。
現(xiàn)在回到我們最初的比較兩個(gè)人臉的問(wèn)題:我們將使用每個(gè)提取的人臉圖像的人臉描述符并將它們與參考數(shù)據(jù)的人臉描述符進(jìn)行比較。也就是說(shuō),我們可以計(jì)算兩個(gè)人臉描述符之間的歐氏距離,并根據(jù)閾值判斷兩個(gè)人臉是否相似(對(duì)于150 x 150大小的人臉圖像,0.6是一個(gè)很好的閾值)。使用歐幾里德距離的方法非常有效,當(dāng)然,你也可以使用任何你選擇的分類(lèi)器。以下gif通過(guò)歐幾里德距離將兩幅人臉圖像進(jìn)行比較:
學(xué)完了人臉識(shí)別的理論,我們可以開(kāi)始編寫(xiě)一個(gè)示例。
編碼
在這個(gè)簡(jiǎn)短的例子中,我們將逐步了解如何在以下顯示多人的輸入圖像上進(jìn)行人臉識(shí)別:
包括腳本
首先,從 dist/face-api.js或者dist/face-api.min.js的minifed版本中獲取最新的構(gòu)建且包括腳本:
<script src =“face-api.js”> </ script>
鏈接:https://github.com/justadudewhohacks/face-api.js/tree/master/dist
如果你使用npm:
npm i face-api.js
加載模型數(shù)據(jù)
根據(jù)應(yīng)用程序的要求,你可以專(zhuān)門(mén)加載所需的模型,但要運(yùn)行完整的端到端示例,我們需要加載人臉檢測(cè),人臉標(biāo)識(shí)和人臉識(shí)別模型。模型文件在repo上可用,下方鏈接中找到。
https://github.com/justadudewhohacks/face-api.js/tree/master/weights
已經(jīng)量化了模型權(quán)重,將模型文件大小減少了75%,以便使你的客戶(hù)端僅加載所需的最小數(shù)據(jù)。此外,模型權(quán)重被分割成最大4MB的塊,以允許瀏覽器緩存這些文件,使得它們只需加載一次。
模型文件可以簡(jiǎn)單地作為靜態(tài)資源(static asset)提供給你的Web應(yīng)用程序,可以在其他地方托管它們,可以通過(guò)指定文件的路徑或url來(lái)加載它們。假設(shè)你在models目錄中提供它們并且資源在public/models下:
const MODEL_URL = '/models' await faceapi.loadModels(MODEL_URL)
或者,如果你只想加載特定模型:
const MODEL_URL = '/models' await faceapi.loadFaceDetectionModel(MODEL_URL) await faceapi.loadFaceLandmarkModel(MODEL_URL) await faceapi.loadFaceRecognitionModel(MODEL_URL)
從輸入圖像接收所有面孔的完整描述
神經(jīng)網(wǎng)絡(luò)接受HTML圖像,畫(huà)布或視頻元素或張量作為輸入。要使用score> minScore檢測(cè)輸入的人臉邊界框,我們只需聲明:
const minConfidence = 0.8 const fullFaceDescriptions = await faceapi.allFaces(input, minConfidence)
完整的人臉描述檢測(cè)結(jié)果(邊界框+分?jǐn)?shù))、人臉標(biāo)志以及計(jì)算出的描述符。正如你所看到的,faceapi.allFaces在前面討論過(guò)的所有內(nèi)容都適用于我們。但是,你也可以手動(dòng)獲取人臉位置和標(biāo)志。如果這是你的目標(biāo),github repo上有幾個(gè)示例。
請(qǐng)注意,邊界框和標(biāo)志位置是相對(duì)于原始圖像/媒體大小。如果顯示的圖像尺寸與原始圖像尺寸不一致,則可以調(diào)整它們的尺寸:
const resized = fullFaceDescriptions.map(fd => fd.forSize(width, height))
我們可以通過(guò)將邊界框繪制到畫(huà)布中來(lái)可視化檢測(cè)結(jié)果:
fullFaceDescription.forEach((fd, i) => { faceapi.drawDetection(canvas, fd.detection, { withScore: true }) })
臉部可 以顯示如下:
fullFaceDescription.forEach((fd, i) => { faceapi.drawLandmarks(canvas, fd.landmarks, { drawLines: true }) })
通常,我所做的可視化工作是在img元素的頂部覆蓋一個(gè)絕對(duì)定位的畫(huà)布,其寬度和高度相同(參閱github示例以獲取更多信息)。
人臉識(shí)別
現(xiàn)在我們知道如何在給定輸入圖像的情況下檢索所有人臉的位置和描述符,即,我們將得到一些圖像,分別顯示每個(gè)人并計(jì)算他們的人臉描述符。這些描述符將成為我們的參考數(shù)據(jù)。
假設(shè)我們有一些可用的示例圖像,我們首先從url獲取圖像,然后使用faceapi.bufferToImage從其數(shù)據(jù)緩沖區(qū)創(chuàng)建HTML圖像元素:
// fetch images from url as blobs const blobs = await Promise.all( ['sheldon.png' 'raj.png', 'leonard.png', 'howard.png'].map( uri => (await fetch(uri)).blob() ) ) // convert blobs (buffers) to HTMLImage elements const images = await Promise.all(blobs.map( blob => await faceapi.bufferToImage(blob) ))
接下來(lái),對(duì)于每個(gè)圖像,我們定位主體的面部并計(jì)算人臉描述符,就像我們之前在輸入圖像時(shí)所做的那樣:
const refDescriptions = await Promsie.all(images.map( img => (await faceapi.allFaces(img))[0] )) const refDescriptors = refDescriptions.map(fd => fd.descriptor)
現(xiàn)在,我們要做的一切就是遍歷輸入圖像的人臉描述,并在參考數(shù)據(jù)中找到距離最近的描述符:
const sortAsc = (a, b) => a - b const labels = ['sheldon', 'raj', 'leonard', 'howard'] const results = fullFaceDescription.map((fd, i) => { const bestMatch = refDescriptors.map( refDesc => ({ label: labels[i], distance: faceapi.euclideanDistance(fd.descriptor, refDesc) }) ).sort(sortAsc)[0] return { detection: fd.detection, label: bestMatch.label, distance: bestMatch.distance } })
如前所述,我們?cè)诖耸褂脷W氏距離作為相似性度量,結(jié)果表明工作得很好。我們最終得到了在輸入圖像中檢測(cè)到的每個(gè)人臉的最佳匹配。
最后,我們可以將邊界框與標(biāo)簽一起繪制到畫(huà)布中以顯示結(jié)果:
// 0.6 is a good distance threshold value to judge // whether the descriptors match or not const maxDistance = 0.6 results.forEach(result => { faceapi.drawDetection(canvas, result.detection, { withScore: false }) const text = `${result.distance < maxDistance ? result.className : 'unkown'} (${result.distance})` const { x, y, height: boxHeight } = detection.getBox() faceapi.drawText( canvas.getContext('2d'), x, y + boxHeight, text ) })
以上我希望你首先了解如何使用api。另外,我建議查看repo中的其他示例。
來(lái)自:ATYUN
crollBy介紹
scrollBy和scrollTo滑動(dòng)的都是是View的內(nèi)容,ViewGroup的子View。scrollBy(int x,int y)是在上一次滑動(dòng)的基礎(chǔ)上在水平方向再滑動(dòng)x,在豎直方向在滑動(dòng)y.
同樣在滑動(dòng)過(guò)程中,不改變View在父容器中的位置(left,top,right,bottom不變);
當(dāng)x>0;View的內(nèi)容從右向左滑動(dòng),當(dāng)x<0;View 的內(nèi)容從左向右滑動(dòng);當(dāng)y>0 View 的內(nèi)容,從下向上滑動(dòng),當(dāng)y<0時(shí) View的內(nèi)容從上向下滑動(dòng)。
2.scrollBy實(shí)例
2.1自定義ScrollByView
public class ScrollByView extends View {
private static String TAG=ScrollByView.class.getSimpleName();
private Paint paint;
private Paint textPaint;
private Paint smallCirclePaint;
public ScrollByView(Context context) {
super(context);
init();
}
public ScrollByView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//設(shè)置ScrollToView的背景
setBackgroundColor(Color.YELLOW);
canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2,paint);
canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/8,smallCirclePaint);
canvas.drawText("使用scrollBy()實(shí)現(xiàn)瞬時(shí)滑動(dòng)",0,40,textPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode=MeasureSpec.getMode(widthMeasureSpec);
int widthSize=MeasureSpec.getSize(widthMeasureSpec);
int heightMode=MeasureSpec.getMode(heightMeasureSpec);
int heightSize=MeasureSpec.getSize(heightMeasureSpec);
//當(dāng)寬和高的測(cè)量模式為MeasureSpec.AT_MOST,將次View的測(cè)量寬高值設(shè)為屏幕寬高的一半
if(widthMode==MeasureSpec.AT_MOST && heightMode==MeasureSpec.AT_MOST){
setMeasuredDimension(Constans.screenWidth/2,Constans.screenHeight/2);
CCLog.d(TAG,"ALL AT_MOST "+"Constans.screenWidth/2="+Constans.screenWidth/2+" Constans.screenHeight/2="+Constans.screenHeight/2);
}else if(widthMode==MeasureSpec.AT_MOST){
//當(dāng)寬的測(cè)量模式為MeasureSpec.AT_MOST,將屏幕寬的一半作為寬的測(cè)量值
setMeasuredDimension(Constans.screenWidth/2,heightSize);
CCLog.d(TAG,"Width_MOST "+heightSize);
}else if(heightMode==MeasureSpec.AT_MOST){
//當(dāng)高的測(cè)量模式為MeasureSpec.AT_MOST,將屏幕高的一半作為寬的測(cè)量值
setMeasuredDimension(widthSize,Constans.screenHeight/2);
CCLog.d(TAG,"Height_MOST "+widthSize);
}
}
//外部調(diào)用;
public void scrollByDelta(int dx, int dy){
//父容器滑動(dòng)子View,滑動(dòng)子View本身
((ViewGroup)getParent()).scrollBy(dx,dy);
//滑動(dòng)View的內(nèi)容
//scrollBy(x,y);
}
private void init(){
paint=new Paint();
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
textPaint=new Paint();
textPaint.setColor(Color.BLACK);
textPaint.setAntiAlias(true);
textPaint.setTextSize(40);
textPaint.setStyle(Paint.Style.STROKE);
smallCirclePaint=new Paint();
smallCirclePaint.setColor(Color.GREEN);
smallCirclePaint.setAntiAlias(true);
smallCirclePaint.setStyle(Paint.Style.FILL);
}
}
2.2布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#33aaaa"
tools:context="com.ifrh.app.scroller.scrollByViewActivity">
<com.ifrh.app.scroller.ScrollByView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:id="@+id/scrollByView" />
<Button
android:layout_width="wrap_content"
android:layout_height="50dp"
android:text="左上角"
android:id="@+id/leftTop"
android:layout_above="@+id/scrollByView"
android:layout_alignLeft="@+id/scrollByView"/>
<Button
android:layout_width="wrap_content"
android:layout_height="50dp"
android:text="右上角"
android:id="@+id/rightTop"
android:layout_above="@+id/scrollByView"
android:layout_alignRight="@+id/scrollByView"/>
<Button
android:layout_width="wrap_content"
android:layout_height="50dp"
android:text="右下角"
android:id="@+id/rightBottom"
android:layout_below="@+id/scrollByView"
android:layout_alignRight="@+id/scrollByView"/>
<Button
android:layout_width="wrap_content"
android:layout_height="50dp"
android:text="左下角"
android:id="@+id/leftBottom"
android:layout_below="@+id/scrollByView"
android:layout_alignLeft="@+id/scrollByView"
/>
</RelativeLayout>
2.3在Activity中使用scrollBy
public class ScrollByActivity extends Activity {
private Button leftTop;
private Button rightTop;
private Button rightBottom;
private Button leftBottom;
private ScrollByView scrollByView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.scroll_by_activity);
leftTop=(Button)findViewById(R.id.leftTop);
rightTop=(Button)findViewById(R.id.rightTop);
rightBottom=(Button)findViewById(R.id.rightBottom);
leftBottom=(Button)findViewById(R.id.leftBottom);
scrollByView=(ScrollByView) findViewById(R.id.scrollByView);
leftTop.setOnClickListener(listener);
rightTop.setOnClickListener(listener);
rightBottom.setOnClickListener(listener);
leftBottom.setOnClickListener(listener);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//在view.PerformClick()中將調(diào)用 view.onClick()方法
leftTop.performClick();
}
},2000);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
rightTop.performClick();
}
},4000);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
leftBottom.performClick();
}
},6000);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
rightBottom.performClick();
}
},8000);
}
private View.OnClickListener listener=new View.OnClickListener(){
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.leftTop:
scrollByView.scrollByDelta(Constans.screenWidth/4,Constans.screenHeight/4);
break;
case R.id.rightTop:
scrollByView.scrollByDelta(-Constans.screenWidth/4,Constans.screenHeight/4);
break;
case R.id.leftBottom:
scrollByView.scrollByDelta(Constans.screenWidth/4,-Constans.screenHeight/4);
break;
case R.id.rightBottom:
scrollByView.scrollByDelta(-Constans.screenWidth/4,-Constans.screenHeight/4);
break;
}
}
};
}
3.演示效果
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。