版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、自定義控件:粘性控件GooView粘性控件了解幾何圖形工具的用法掌握畫不規(guī)則圖形的方法應(yīng)用場景:未讀提醒,效果圖:繪制一幀的效果畫一幀粘性控件的步驟分析 1畫一個固定圓 2畫一個拖拽圓 3畫中間連接部分 將中間連接部分水平放置,四個角的坐標(biāo)定為固定值,分別標(biāo)記上點的編號,矩形中心的點為控件點,畫曲線時用自定義一個GooView 繼承Viewpublic class GooView extends View private Paint paint; public GooView(Context context) this(context,null); public GooView(Context
2、 context, AttributeSet attrs) this(context, attrs,0); public GooView(Context context, AttributeSet attrs, int defStyle) super(context, attrs, defStyle); /初始化畫筆 paint = new Paint(); paint.setAntiAlias(true); paint.setColor(Color.RED); Override protected void onDraw(Canvas canvas) super.onDraw(canvas)
3、; /畫中間連接部分 Path path = new Path(); /跳到點1,默認為(0f,0f) path.moveTo(250f, 250f); /從點1->點2 畫曲線 path.quadTo(150f, 300f, 50f, 250f); /從點2->點3 畫直線 path.lineTo(50f, 350f); /從點3->點4 畫曲線 path.quadTo(150f, 300f, 250f, 350f); canvas.drawPath(path, paint); /畫拖拽圓 canvas.drawCircle(90f, 90f, 16f, paint); /
4、畫固定圓 canvas.drawCircle(150f, 150f, 12f, paint); 第20-30 行用Path 畫中間曲線部分 第25 行quadTo(x1,y1,x2,y2)方法可以畫當(dāng)前所在點到x2,y2 間的一條曲線,x1,y1 是當(dāng)前點與x2,y2 間的一個控件點,它的位置決定曲線彎曲的方向和弧度,將GooView 顯示到MainActivity 中public class MainActivity extends Activity Override protected void onCreate(Bundle savedInstanceState) requestWind
5、owFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); setContentView(new GooView(this); 貝塞爾曲線二階貝塞爾曲線,三階貝塞爾曲線分別給拖拽圓,固定圓的圓心,半徑,兩個附著點命名,修改GooView 的onDraw()方法protected void onDraw(Canvas canvas) super.onDraw(canvas); /固定圓的兩個附著點 PointF mStickPoints = new PointF new PointF(250f, 250f),ne
6、w PointF(250f, 350f) ; /固定圓的兩個附著點 PointF mDragPoints = new PointF new PointF(50f, 250f),new PointF(50f, 350f) ; /控制點 PointF mControlPoint = new PointF(150f, 300f); /畫中間連接部分 Path path = new Path(); /跳到點1,默認為(0f,0f) path.moveTo(mStickPoints0.x, mStickPoints0.y); /從點1->點2 畫曲線 path.quadTo(mControlPoi
7、nt.x, mControlPoint.y, mDragPoints0.x, mDragPoints0.y); /從點2->點3 畫直線 path.lineTo( mDragPoints1.x, mDragPoints1.y); /從點3->點4 畫曲線 path.quadTo(mControlPoint.x, mControlPoint.y, mStickPoints1.x, mStickPoints1.y); canvas.drawPath(path, paint); /畫拖拽圓 /拖拽圓圓心 PointF mDragCenter = new PointF(90f, 90f);
8、 /拖拽圓半徑 float mDragRadius = 16f; canvas.drawCircle(mDragCenter.x, mDragCenter.y, mDragRadius, paint); /畫固定圓 /固定圓圓心 PointF mStickCenter = new PointF(150f, 150f); /固定圓半徑 float mStickRadius = 12f; canvas.drawCircle(mStickCenter.x, mStickCenter.y, mStickRadius, paint);第3-14 行替換附著點及控制點 第30-40 行替換拖拽圓及固定圓的
9、圓心及半徑 將替換后的變量轉(zhuǎn)換成GooView 的成員變量/ 固定圓圓心PointF mStickCenter = new PointF(150f, 150f);/ 固定圓半徑float mStickRadius = 12f;/ 拖拽圓圓心PointF mDragCenter = new PointF(90f, 90f);/ 拖拽圓半徑float mDragRadius = 16f;/ 固定圓的兩個附著點PointF mStickPoints = new PointF new PointF(250f, 250f), new PointF(250f, 350f) ;/ 固定圓的兩個附著點Poin
10、tF mDragPoints = new PointF new PointF(50f, 250f), new PointF(50f, 350f) ;/ 控制點PointF mControlPoint = new PointF(150f, 300f);Overrideprotected void onDraw(Canvas canvas) super.onDraw(canvas); / 畫中間連接部分 Path path = new Path(); / 跳到點1,默認為(0f,0f) path.moveTo(mStickPoints0.x, mStickPoints0.y); / 從點1->
11、;點2 畫曲線 path.quadTo(mControlPoint.x, mControlPoint.y, mDragPoints0.x, mDragPoints0.y); / 從點2->點3 畫直線 path.lineTo(mDragPoints1.x, mDragPoints1.y); / 從點3->點4 畫曲線 path.quadTo(mControlPoint.x, mControlPoint.y, mStickPoints1.x, mStickPoints1.y); canvas.drawPath(path, paint); / 畫拖拽圓 canvas.drawCircl
12、e(mDragCenter.x, mDragCenter.y, mDragRadius, paint); / 畫固定圓 canvas.drawCircle(mStickCenter.x, mStickCenter.y, mStickRadius, paint);拖拽圓和固定圓的圓心和半徑已知,角3 的正弦值為兩圓心縱坐標(biāo)之差比上橫坐標(biāo)之差,則角3 的角度可知,則角1 可知,AB,AC 的長度即可計算出來,mDragPoints0的坐標(biāo)可以計算出來,同理其它三個附著點坐標(biāo)也可知。mControlPoint 為兩圓心連線的中點幾何圖形工具/* * 幾何圖形工具 */public class Geo
13、metryUtil /* * As meaning of method name. * 獲得兩點之間的距離 * param p0 * param p1 * return */ public static float getDistanceBetween2Points(PointF p0, PointF p1) float distance = (float) Math.sqrt(Math.pow(p0.y - p1.y, 2) + Math.pow(p0.x - p1.x, 2); return distance; /* * Get middle point between p1 and p2
14、. * 獲得兩點連線的中點 * param p1 * param p2 * return */ public static PointF getMiddlePoint(PointF p1, PointF p2) return new PointF(p1.x + p2.x) / 2.0f, (p1.y + p2.y) / 2.0f); /* * Get point between p1 and p2 by percent. * 根據(jù)百分比獲取兩點之間的某個點坐標(biāo) * param p1 * param p2 * param percent * return */ public static Poi
15、ntF getPointByPercent(PointF p1, PointF p2, float percent) return new PointF(evaluateValue(percent, p1.x , p2.x), evaluateValue(percent, p1.y , p2.y); /* * 根據(jù)分度值,計算從start 到end 中,fraction 位置的值。fraction 范圍為0 -> 1 * param fraction * param start * param end * return */ public static float evaluateVal
16、ue(float fraction, Number start, Number end) return start.floatValue() + (end.floatValue() - start.floatValue() * fraction; /* * Get the point of intersection between circle and line. * 獲取通過指定圓心,斜率為lineK 的直線與圓的交點。 * * param pMiddle The circle center point. * param radius The circle radius. * param l
17、ineK The slope of line which cross the pMiddle. * return */ public static PointF getIntersectionPoints(PointF pMiddle, float radius, DoublelineK) PointF points = new PointF2; float radian, xOffset = 0, yOffset = 0; if(lineK != null) radian= (float) Math.atan(lineK); xOffset = (float) (Math.sin(radia
18、n) * radius); yOffset = (float) (Math.cos(radian) * radius); else xOffset = radius; yOffset = 0; points0 = new PointF(pMiddle.x + xOffset, pMiddle.y - yOffset); points1 = new PointF(pMiddle.x - xOffset, pMiddle.y + yOffset); return points; 利用幾何圖形工具類計算四個附著點坐標(biāo)及控件點坐標(biāo)protected void onDraw(Canvas canvas)
19、 super.onDraw(canvas); float yOffset = mStickCenter.y - mDragCenter.y; float xOffset = mStickCenter.x - mDragCenter.x; Double lineK = null; if(xOffset != 0) /xOffset 分母不能為0 lineK = (double) (yOffset/xOffset); /計算四個附著點 mDragPoints = GeometryUtil.getIntersectionPoints(mDragCenter, mDragRadius, lineK);
20、 mStickPoints = GeometryUtil.getIntersectionPoints(mStickCenter, mStickRadius, lineK); /一個控制點 mControlPoint = GeometryUtil.getMiddlePoint(mDragCenter, mStickCenter); / 畫中間連接部分 Path path = new Path(); / 跳到點1,默認為(0f,0f) path.moveTo(mStickPoints0.x, mStickPoints0.y); / 從點1->點2 畫曲線 path.quadTo(mContr
21、olPoint.x, mControlPoint.y, mDragPoints0.x, mDragPoints0.y); / 從點2->點3 畫直線 path.lineTo(mDragPoints1.x, mDragPoints1.y); / 從點3->點4 畫曲線 path.quadTo(mControlPoint.x, mControlPoint.y, mStickPoints1.x, mStickPoints1.y); canvas.drawPath(path, paint); / 畫拖拽圓 canvas.drawCircle(mDragCenter.x, mDragCent
22、er.y, mDragRadius, paint); / 畫固定圓 canvas.drawCircle(mStickCenter.x, mStickCenter.y, mStickRadius, paint);第3-17 行計算四個附著點及控制點坐標(biāo)1.4 計算固定圓半徑GooView 重寫onSizeChanged()方法,計算狀態(tài)欄高度Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) super.onSizeChanged(w, h, oldw, oldh); /獲取狀態(tài)欄的高度,傳入一個顯示在屏幕
23、上的view 即可 statusBarHeight = Utils.getStatusBarHeight(this);Utils.Javapublic class Utils public static Toast mToast; public static void showToast(Context mContext, String msg) if (mToast = null) mToast = Toast.makeText(mContext, "", Toast.LENGTH_SHORT); mToast.setText(msg); mToast.show(); /
24、* * 獲取狀態(tài)欄高度 * * param v * return */ public static int getStatusBarHeight(View v) if (v = null) return 0; Rect frame = new Rect(); v.getWindowVisibleDisplayFrame(frame); return frame.top; 修改onDraw()方法protected void onDraw(Canvas canvas) super.onDraw(canvas); float yOffset = mStickCenter.y - mDragCent
25、er.y; float xOffset = mStickCenter.x - mDragCenter.x; Double lineK = null; if(xOffset != 0) /xOffset 分母不能為0 lineK = (double) (yOffset/xOffset); /計算四個附著點 mDragPoints = GeometryUtil.getIntersectionPoints(mDragCenter, mDragRadius, lineK); mStickPoints = GeometryUtil.getIntersectionPoints(mStickCenter,
26、mStickRadius, lineK); /一個控制點 mControlPoint = GeometryUtil.getMiddlePoint(mDragCenter, mStickCenter); /移動畫布 canvas.save(); canvas.translate(0, -statusBarHeight); / 畫中間連接部分 Path path = new Path(); / 跳到點1,默認為(0f,0f) path.moveTo(mStickPoints0.x, mStickPoints0.y); / 從點1->點2 畫曲線 path.quadTo(mControlPoi
27、nt.x, mControlPoint.y, mDragPoints0.x, mDragPoints0.y); / 從點2->點3 畫直線 path.lineTo(mDragPoints1.x, mDragPoints1.y); / 從點3->點4 畫曲線 path.quadTo(mControlPoint.x, mControlPoint.y, mStickPoints1.x, mStickPoints1.y); canvas.drawPath(path, paint); / 畫拖拽圓 canvas.drawCircle(mDragCenter.x, mDragCenter.y,
28、 mDragRadius, paint); / 畫固定圓 canvas.drawCircle(mStickCenter.x, mStickCenter.y, mStickRadius, paint); canvas.restore();第18-20 行把畫布向上移動狀態(tài)欄的高度,移動前需要保存一下當(dāng)前狀態(tài),做完操作后需要恢復(fù)一下狀態(tài),由于在onTouchEvent()中用的是getRawX(),getRawY()獲取的是相對屏幕的坐標(biāo),所以GooView畫圖操作時需要向上移到一個狀態(tài)欄的高度才能剛好和手指重合拖拽圓跟隨手指移動時,隨著拖拽與固定圓的距離的變大,固定圓的半徑越來越小/允許的最大距
29、離float farestDistance = 80f;/* * 通過兩圓圓心的距離,計算固定圓的半徑 * return */private float computeStickRadius() /通過幾何圖形工具類可以計算出兩圓圓心的距離,distance 是可以大于80f; float distance = GeometryUtil.getDistanceBetween2Points(mDragCenter, mStickCenter); /需要的是0.0f -> 1.0f 的值,所在大于80f 讓distance 等于80f distance = Math.min(farestDi
30、stance, distance); float percent = distance/farestDistance; /需要固定圓心半徑在12f -> 3f 間變化,可以利用類型估值器 return evaluate(percent, mStickRadius, mStickRadius*0.25f);/FloatEvaluator.java 中拷貝public Float evaluate(float fraction, Number startValue, Number endValue) float startFloat = startValue.floatValue(); re
31、turn startFloat + fraction * (endValue.floatValue() - startFloat);protected void onDraw(Canvas canvas) super.onDraw(nvas); /通過兩圓圓心的距離,計算固定圓的半徑 float tempStickRadius = computeStickRadius(); float yOffset = mStickCenter.y - mDragCenter.y; float xOffset = mStickCenter.x - mDragCenter.x; Double lineK =
32、null; if(xOffset != 0) lineK = (double) (yOffset/xOffset); /計算四個附著點 mDragPoints = GeometryUtil.getIntersectionPoints(mDragCenter, mDragRadius,lineK); mStickPoints = GeometryUtil.getIntersectionPoints(mStickCenter, tempStickRadius,lineK); /一個控制點 mControlPoint = GeometryUtil.getMiddlePoint(mDragCenter
33、, mStickCenter); /移動畫布 canvas.save(); canvas.translate(0, -statusBarHeight); / 畫中間連接部分 Path path = new Path(); / 跳到點1,默認為(0f,0f) path.moveTo(mStickPoints0.x, mStickPoints0.y); / 從點1->點2 畫曲線 path.quadTo(mControlPoint.x, mControlPoint.y, mDragPoints0.x, mDragPoints0.y); / 從點2->點3 畫直線 path.lineTo
34、(mDragPoints1.x, mDragPoints1.y); / 從點3->點4 畫曲線 path.quadTo(mControlPoint.x, mControlPoint.y, mStickPoints1.x, mStickPoints1.y); canvas.drawPath(path, paint); / 畫拖拽圓 canvas.drawCircle(mDragCenter.x, mDragCenter.y, mDragRadius, paint); / 畫固定圓 canvas.drawCircle(mStickCenter.x, mStickCenter.y, tempS
35、tickRadius, paint); canvas.restore();第2 行定義最大的拖拽距離為80f 第7-24 行拖拽圓與固定圓的距離大于80f 時,取80f,通過兩圓圓心的距離與80f 相對可以求出一個0.0f 到1.0f 的值,再通過估值器可以獲得固定圓的半徑在mStickRadius,mStickRadius*0.25f 間的變化值 第27-28 行通過兩圓圓心的距離計算固定圓的半徑tempStickRadius 第39,67 行將mStickRadius 替換成計算出來的半徑tempStickRadius事件處理事件處理的分析1超出最大范圍:拖拽圓與固定圓斷開,松手后消失 2
36、超出最大范圍:又放回去,恢復(fù) 3沒有超出最大范圍:松手,回彈動畫,恢復(fù)事件處理的實現(xiàn)修改onTouchEvent()方法/是否已經(jīng)消失private boolean isDisappear = false;/是否超出范圍private boolean isOutOfRange = false;public boolean onTouchEvent(MotionEvent event) float x; float y; switch (event.getAction() case MotionEvent.ACTION_DOWN: /重置變量 isDisappear = false; isOut
37、OfRange = false; x = event.getRawX(); y = event.getRawY(); updateDragCenter(x, y); break; case MotionEvent.ACTION_MOVE: x = event.getRawX(); y = event.getRawY(); updateDragCenter(x, y); float d = GeometryUtil.getDistanceBetween2Points(mDragCenter, mStickCenter); / 超出范圍斷開 if (d > farestDistance) i
38、sOutOfRange = true; invalidate(); break; case MotionEvent.ACTION_UP: if (isOutOfRange) / 剛剛超出了范圍 float dis = GeometryUtil.getDistanceBetween2Points(mDragCenter, mStickCenter); if (dis > farestDistance) / 超出范圍,松手,斷開,消失 isDisappear = true; invalidate(); else / 超出范圍,斷開,又放回去了,恢復(fù) updateDragCenter(mSti
39、ckCenter.x, mStickCenter.y); else / 沒有超出范圍,松手,回彈,恢復(fù) final PointF startP = new PointF(mDragCenter.x, mDragCenter.y); ValueAnimator animator = ValueAnimator.ofFloat(1.0f); animator.setDuration(500); / 插值器,回彈效果 animator.setInterpolator(new OvershootInterpolator(4); animator.addUpdateListener(new Animat
40、orUpdateListener() Override public void onAnimationUpdate(ValueAnimator animation) / 生成0.0f ->1.0f 間的值 float percent = animation.getAnimatedFraction(); / 計算從開始點startP 到mStickCenter 間的所有值 PointF p = GeometryUtil.getPointByPercent(startP, mStickCenter, percent); updateDragCenter(p.x, p.y); ); anima
41、tor.start(); break; default: break; return true;第1-2 行創(chuàng)建兩個布爾變量記錄是否已經(jīng)消失及是否超出范圍 第11-12 行手指重新按下時,重置變量 第21-27 行拖拽過程中記錄是否超出范圍 第32-38 行超出范圍,松手,消失,標(biāo)記當(dāng)前為消失狀態(tài) 第39-41 行超出范圍,又放回去了,需要恢復(fù),直接更新拖拽圓圓心為固定圓心即可 第45-62 行沒有超出范圍,松手,需要回彈動畫,恢復(fù) 修改onDraw()方法protected void onDraw(Canvas canvas) super.onDraw(canvas); / 通過兩圓圓心的距
42、離,計算固定圓的半徑 float tempStickRadius = computeStickRadius(); float yOffset = mStickCenter.y - mDragCenter.y; float xOffset = mStickCenter.x - mDragCenter.x; Double lineK = null; if (xOffset != 0) lineK = (double) (yOffset / xOffset); / 計算四個附著點 mDragPoints = GeometryUtil.getIntersectionPoints(mDragCenter
43、, mDragRadius, lineK); mStickPoints = GeometryUtil.getIntersectionPoints(mStickCenter, tempStickRadius, lineK); / 一個控制點 mControlPoint = GeometryUtil.getMiddlePoint(mDragCenter, mStickCenter); / 移動畫布 canvas.save(); canvas.translate(0, -statusBarHeight); / 畫出最大范圍(參考) / 只畫邊線 paint.setStyle(Style.STROKE
44、); canvas.drawCircle(mStickCenter.x, mStickCenter.y, farestDistance, paint); / 填充 paint.setStyle(Style.FILL); if(!isDisappear) /沒有消失時,才繪制內(nèi)容 if (!isOutOfRange) /沒有超出范圍時,才畫連接部分和固定圓 / 畫中間連接部分 Path path = ew Path(); / 跳到點1,默認為(0f,0f) path.moveTo(mStickPoints0.x, mStickPoints0.y); / 從點1->點2 畫曲線 path.q
45、uadTo(mControlPoint.x, mControlPoint.y, mDragPoints0.x, mDragPoints0.y); / 從點2->點3 畫直線 path.lineTo(mDragPoints1.x, mDragPoints1.y); / 從點3->點4 畫曲線 path.quadTo(mControlPoint.x, mControlPoint.y, mStickPoints1.x, mStickPoints1.y); canvas.drawPath(path, paint); / 畫固定圓 canvas.drawCircle(mStickCenter.x, mStickCenter.y, tempStickRadius, paint); / 畫拖拽圓 ca
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 貴陽職業(yè)技術(shù)學(xué)院《試驗設(shè)計與數(shù)據(jù)處理》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025上海市安全員-C證考試(專職安全員)題庫附答案
- 2025江蘇省安全員《B證》考試題庫及答案
- 2025海南省建筑安全員C證考試(專職安全員)題庫附答案
- 廣州中醫(yī)藥大學(xué)《形體訓(xùn)練(Ⅱ)》2023-2024學(xué)年第一學(xué)期期末試卷
- 廣州應(yīng)用科技學(xué)院《環(huán)境藝術(shù)專題設(shè)計》2023-2024學(xué)年第一學(xué)期期末試卷
- 廣州現(xiàn)代信息工程職業(yè)技術(shù)學(xué)院《運動解剖學(xué)》2023-2024學(xué)年第一學(xué)期期末試卷
- 廣州鐵路職業(yè)技術(shù)學(xué)院《針織物設(shè)計與試織》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025四川建筑安全員B證(項目經(jīng)理)考試題庫
- 2025年福建建筑安全員《A證》考試題庫及答案
- 2024年股東股權(quán)繼承轉(zhuǎn)讓協(xié)議3篇
- 2025年中央歌劇院畢業(yè)生公開招聘11人歷年高頻重點提升(共500題)附帶答案詳解
- 北京市高校課件 開天辟地的大事變 中國近代史綱要 教學(xué)課件
- 監(jiān)事會年度工作計劃
- 2024年認證行業(yè)法律法規(guī)及認證基礎(chǔ)知識
- SVG無功補償培訓(xùn)
- 新生兒聽力篩查技術(shù)規(guī)范衛(wèi)生部2010年版
- 大貓英語分級閱讀 六級1 Arthur's Fantastic Party課件
- SCA自動涂膠系統(tǒng)培訓(xùn)講義
- LEC法取值標(biāo)準對照表
- 華中數(shù)控車床編程及操作
評論
0/150
提交評論