package com.zql.android.led; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.support.annotation.ColorInt; import android.text.TextPaint; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.ViewTreeObserver; import java.util.concurrent.Executors; /** * Created by scott on 2017/6/14. */ public class LEDView extends SurfaceView implements SurfaceHolder.Callback,Runnable{ private SurfaceHolder mHolder; private Handler mHandler; private HandlerThread mThread; private String mLEDStr =""; private int mLEDHight = 0, mLEDWidth = 0; private final int kFPS = 1000/20; private TextPaint mTextPaint ; private int kTextSize = 30; private int kRawBitmapHight = 40; private int mLEDColor = Color.parseColor("#EC3A36"); private int kTextBaseLine = kRawBitmapHight/2 + kTextSize/2 - kTextSize/10; private LEDData mLEDData; private long mT1,mT2,mTD; private boolean mIsDestory = false; private final String kSpace = ""; public LEDView(Context context) { this(context,null); } public LEDView(Context context, AttributeSet attrs) { this(context,attrs,0); } public LEDView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public void setLED(String str ,@ColorInt int ledColor, int ledTextSize,int ledPixel){ if(str == null || str.trim().length() == 0){ mLEDStr = kSpace + "Hello LED \uD83D\uDE00"; }else { mLEDStr = kSpace + str; } mLEDColor = ledColor; if(ledTextSize > 0){ kTextSize = ledTextSize; } if(ledPixel>0){ kRawBitmapHight = ledPixel; } mLEDData = null; makeRawBitmap(); } public void setLEDContent(String content){ if(content == null || content.trim().length() == 0){ mLEDStr = kSpace + "Hello LED \uD83D\uDE00"; }else { mLEDStr = kSpace+content; } mLEDData = null; makeRawBitmap(); } public void setLEDTextColor(int color){ mLEDColor = color; mLEDData = null; makeRawBitmap(); } public void setLEDSize(int size){ kRawBitmapHight = size; mLEDData = null; makeRawBitmap(); } public void setLEDTextSize(int size){ kTextSize = size; mLEDData = null; makeRawBitmap(); } public int getLEDColor(){ return mLEDColor; } private void init(){ mHolder = getHolder(); mHolder.addCallback(this); mThread = new HandlerThread("led-looper"); mThread.start(); mHandler = new Handler(mThread.getLooper()); mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { mLEDHight = getWidth(); mLEDWidth = getHeight(); Log.d("scott"," led size " + " h : " + mLEDHight + " w : " + mLEDWidth); getViewTreeObserver().removeOnPreDrawListener(this); return false; } }); } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { Log.d("scott"," surface creates"); mIsDestory = false; if(mLEDData == null){ mHandler.postDelayed(this,kFPS); setLED(mLEDStr,mLEDColor,kTextSize,kRawBitmapHight); }else { mHandler.postDelayed(this,kFPS); } } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { Log.d("scott"," surface Changed"); } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { Log.d("scott"," surface destroy"); mIsDestory = true; } private void makeRawBitmap(){ if(mLEDStr == null || mLEDStr.trim().length() == 0) return; if(mLEDData != null) return; Executors.newSingleThreadExecutor().execute(new Runnable() { @Override public void run() { synchronized (LEDView.this){ mLEDData = null; } mTextPaint.setColor(mLEDColor); mTextPaint.setTextSize(kTextSize); kTextBaseLine = kRawBitmapHight/2 + kTextSize/2 - kTextSize/10; float textLen = mTextPaint.measureText(mLEDStr); Bitmap bitmap = Bitmap.createBitmap((int)textLen,kRawBitmapHight, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.drawText(mLEDStr,0,kTextBaseLine,mTextPaint); Canvas LEDCanvas = mHolder.lockCanvas(); if(LEDCanvas != null){ try { LEDFrame ledFrame = new LEDFrame(bitmap.getWidth(),bitmap.getHeight()); initLEDFrame(ledFrame,bitmap); bitmap.recycle(); int scale = mLEDWidth/kRawBitmapHight; int screenW = mLEDHight/scale; Log.d("scott"," screen w = " + screenW); LEDData ledData = new LEDData(); ledData.frame = ledFrame; ledData.pixelH = kRawBitmapHight; ledData.pixelW = (int)textLen; ledData.scale = scale; ledData.ledScreenH = kRawBitmapHight; ledData.LedScreenW = screenW; synchronized (LEDView.this){ mLEDData = ledData; } }catch (Exception e){ e.printStackTrace(); }finally { mHolder.unlockCanvasAndPost(LEDCanvas); } } } }); } private void initLEDFrame(LEDFrame ledFrame,Bitmap bitmap){ int w = bitmap.getWidth(); int h = bitmap.getHeight(); Log.d("scott","bitmap w : " + w + " bitmap h = " + h); for(int x = 0;x<w;x++){ for(int y = 0;y<h;y++){ ledFrame.fillData(y,x,bitmap.getPixel(x,y)); } } } @Override public void run() { mT1 = System.currentTimeMillis(); if(mIsDestory) return; if(mHolder == null) return; Canvas LEDCanvas = mHolder.lockCanvas(); if(LEDCanvas != null){ try { if(mLEDData != null){ LEDCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); int fixH = mLEDData.getFixLEDHeight(); int fixW = mLEDData.getFixLEDWidth(); for(int i = 0;i<fixH;i+=2){ for(int j = 0;j<fixW;j+=2){ int pX = j*mLEDData.scale; int pY = i*mLEDData.scale; if(mLEDData.getPixelColor(i,j) != 0){ mTextPaint.setColor(mLEDData.getPixelColor(i,j)); LEDCanvas.drawCircle(pX,pY,mLEDData.scale/2,mTextPaint); } } } mLEDData.nextFrame(); } }catch (Exception e){ e.printStackTrace(); }finally { mHolder.unlockCanvasAndPost(LEDCanvas); } } mT2 = System.currentTimeMillis(); mTD = mT2 - mT1; if(mTD < kFPS){ mHandler.postDelayed(this,kFPS-mTD); }else { mHandler.post(this); } } private class LEDFrame{ int[][] frameData; LEDFrame(int w,int h){ frameData = new int[h][w]; } void fillData(int r,int c,int value){ frameData[r][c] = value; } void dump(){ StringBuilder stringBuilder = new StringBuilder(); for(int i = 0;i<frameData.length;i++){ for(int j = 0;j<frameData[i].length;j++){ stringBuilder.append(frameData[i][j] + " "); } stringBuilder.append("\n"); } Log.d("scott",stringBuilder.toString()); } int[][] getData(){ return frameData; } } private class LEDData{ LEDFrame frame; int scale; int pixelW; int pixelH; int ledScreenH; int LedScreenW; int delta = 0; void nextFrame(){ if(LedScreenW >= pixelW) return; delta ++ ; } int getFixLEDWidth(){ return pixelW<=LedScreenW?pixelW:LedScreenW; } int getFixLEDHeight(){ return pixelH; } int getPixelColor(int i,int j){ if(j+delta< pixelW){ return frame.frameData[i][j + delta]; }else { return frame.frameData[i][(j + delta)%pixelW]; } } } }