您好,登錄后才能下訂單哦!
本文實例為大家分享了Android軌跡動畫的具體代碼,供大家參考,具體內容如下
二、需求描述
年中那會兒基友的公司給他了一張只有一條曲線的圖,想讓他按照曲線的軌跡動態展示整個曲線,然而基友忙于把妹,一個饅頭的代價收買了我,于是幫他寫了代碼。先看下實現效果
上原始圖(原始圖的軌跡曲線是白色的,其他部分是透明的,這里為了便于觀察,我將背景調為黑色)
三、分析實現
講道理,剛拿到這個圖片的時候我也有點懵逼,一個毫無規律的曲線很顯然不能通過簡單的方程式去描述點的具體位置,甚至想說設計直接給個動畫豈不美滋滋......
吐槽歸吐槽,需求還是要實現的,而且這個需求是有不少常見的方法可以進行實現的,比如上下兩層圖片保持一直,上層不斷從左到右將原圖縱向像素清除,然后將設計給的圖片也按照從左到友的順去繪制上去。不過這種方法的可擴展性太差,底層的圖片發生改變(滑動、變色)上層也需要進行配合。
這里使用方法是:將圖片中有色像素在圖片上的位置按照比例映射到要繪制的View中。
比如,原圖大小是200*100,要去做展示的View的尺寸大小是450*300,某點在原圖中位于x100,y20的位置,那么它在view中的位置應該為225,60。也就是說將該點在途中的位置比上原圖對應尺寸然后在乘以View的尺寸即可。
軌跡的獲取可以通過獲取全部的像素點顏色,因為透明的必然不是軌跡,所以判斷Alpha值即可,又因為軌跡是一條線,當我們使用Path連點的時候為了盡量減少不必要點的連接,我這里通過平均值的方式將曲線的寬度降為1。
由于點的位置是按照尺寸比例計算的,所以無論要展示的圖片尺寸有多奇葩,都可以完美適配上去
四、實現代碼
public class TestView extends View implements ViewTreeObserver.OnGlobalLayoutListener{ private Paint paint = new Paint(); private Bitmap bitmap; private int[]local; boolean enter = false; int count; ViewTreeObserver observer; Canvas canvas; float lastX = 0; float lastY = 0; public TestView(Context context) { super(context); } public TestView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); observer = this.getViewTreeObserver(); observer.addOnGlobalLayoutListener(this); getImageFromAssetsFile("target.png");//讀取圖片 } public TestView(Context context, AttributeSet attrs) { super(context, attrs); observer = this.getViewTreeObserver(); observer.addOnGlobalLayoutListener(this); getImageFromAssetsFile("target.png"); } private void getImageFromAssetsFile(String fileName) { AssetManager am = getResources().getAssets(); try { InputStream is = am.open(fileName); bitmap = BitmapFactory.decodeStream(is); is.close(); } catch (IOException e) { e.printStackTrace(); } } private void filterColor(){ int w = bitmap.getWidth(); int h = bitmap.getHeight(); int[]pixels = new int[w*h]; local = new int[w];//以原圖寬為單位,保存點在原圖Y軸上的位置 bitmap.getPixels(pixels,0,bitmap.getWidth(),0,0,bitmap.getWidth(),bitmap.getHeight()); for(int i = 0; i < w; i++){ int lenght = 0; int total = 0; for(int j = 0;j<h;j++){ if (bitmap.getPixel(i, j) !=0) { lenght++; total+=j; } } System.out.println(lenght+""); if(lenght<15||((float)i/(float) w)<0.85) local[i] = total/lenght; else break; } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(enter) { paint.setAntiAlias(true); //設置畫筆為無鋸齒 paint.setColor(Color.WHITE); //設置畫筆顏色 canvas.drawColor(Color.TRANSPARENT); //透明背景 paint.setStrokeWidth((float) 6.0); //線寬 paint.setStyle(Paint.Style.STROKE); Path path = new Path(); path.moveTo(0, (((float) getMeasuredHeight()-25) / (float)bitmap.getHeight()) * (float) local[0]+7); if (count <= bitmap.getWidth()) { if(count<bitmap.getWidth()) count++; for (int i = 1; i < count - 1; i++) { if(local[i]>0) { path.lineTo((getMeasuredWidth() / (float) bitmap.getWidth()) * (float) i, (((float) getMeasuredHeight()-25) / (float) bitmap.getHeight()) * (float) local[i]+7); lastX = (getMeasuredWidth() / (float) bitmap.getWidth()) * (float) i; lastY = (((float) getMeasuredHeight()-25 )/ (float) bitmap.getHeight()) * (float) local[i]; } } } if(count<bitmap.getWidth()) postInvalidate(); else { count = 0; postInvalidate(); } canvas.drawPath(path, paint); paint.setStyle(Paint.Style.FILL); canvas.drawCircle(lastX, lastY+7, 7, paint); // } }else{ this.canvas = canvas; } } @Override public void onGlobalLayout() { filterColor(); enter = true; postInvalidate(); } }
當然了,這個代碼也只是給基友交差用的,還有不少地方能做優化,比如:將圖片讀取放在子線程、對圖片大小進行判斷避免OOM、大圖加載圖片壓縮。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。