国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android實用控件自定義逼真相機光圈View

2019-12-12 05:42:07
字體:
來源:轉載
供稿:網友

最近手機界開始流行雙攝像頭,大光圈功能也應用而生。所謂大光圈功能就是能夠對照片進行后期重新對焦,其實現的原理主要是對拍照期間獲取的深度圖片與對焦無窮遠的圖像通過算法來實現重新對焦的效果。 

在某雙攝手機的大光圈操作界面有個光圈的操作圖標,能夠模擬光圈調節時的真實效果,感覺還不錯,于是想著實現該效果。現在把我的實現方法貢獻給大家,萬一你們公司也要做雙攝手機呢?( ̄┰ ̄*) 

首先,百度一下光圈圖片,觀察觀察,就可以發現其關鍵在于計算不同的光圈值時各個光圈葉片的位置。為了計算簡便,我以六個直邊葉片的光圈效果為例來實現(其他形式,比如七個葉片,也就是位置計算稍微沒那么方便;而一些圓弧的葉片,只要滿足葉片兩邊的圓弧半徑是一樣的就行。為什么要圓弧半徑一樣呢?仔細觀察就可以發現,相鄰兩葉片之間要相互滑動,而且要保持一樣的契合距離,根據我曾今小學幾何科打滿分的經驗可以判斷出,等徑的圓弧是不錯滴,其他高級曲線能不能實現該效果,請問數學家( ̄┰ ̄*)!其他部分原理都是一樣的)。  

制作效果圖: 

先說明一下本自定義view的主要內容:
 1.本效果的實現就是在光圈內六邊形六個角上分別繪制六個光圈葉片
 2.根據不同的光圈值計算出內六邊形的大小,從而計算每個六邊形的頂點的位置
 3.設計葉片。也可以讓美工MM提供,本方案是自己用代碼畫的。注意預留葉片之間的間隔距離以及每個葉片的角度為60°
 4.定義顏色、間隔等自定義屬性
 5.上下滑動可以調節光圈大小
 6.提供光圈值變動的監聽接口 

代碼 
可以在GitHub上下載:https://github.com/willhua/CameraAperture.git 

package com.example.cameraaperture;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.Bitmap.Config;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PointF;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;/** * 上下滑動可以調節光圈大小; * 調用setApertureChangedListener設置光圈值變動監聽接口; * 繪制的光圈最大直徑將填滿整個view * @author willhua http://www.cnblogs.com/willhua/ *  */public class ApertureView extends View {  public interface ApertureChanged {    public void onApertureChanged(float newapert);  }  private static final float ROTATE_ANGLE = 30;  private static final String TAG = "ApertureView";  private static final float COS_30 = 0.866025f;  private static final int WIDTH = 100; // 當設置為wrap_content時測量大小  private static final int HEIGHT = 100;  private int mCircleRadius;  private int mBladeColor;  private int mBackgroundColor;  private int mSpace;  private float mMaxApert = 1;  private float mMinApert = 0.2f;  private float mCurrentApert = 0.5f;  //利用PointF而不是Point可以減少計算誤差,以免葉片之間間隔由于計算誤差而不均衡  private PointF[] mPoints = new PointF[6];   private Bitmap mBlade;  private Paint mPaint;  private Path mPath;  private ApertureChanged mApertureChanged;  private float mPrevX;  private float mPrevY;  public ApertureView(Context context, AttributeSet attrs) {    super(context, attrs);    init(context, attrs);  }  private void init(Context context, AttributeSet attrs) {    //讀取自定義布局屬性    TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ApertureView);    mSpace = (int)array.getDimension(R.styleable.ApertureView_blade_space, 5);    mBladeColor = array.getColor(R.styleable.ApertureView_blade_color, 0xFF000000);    mBackgroundColor = array.getColor(R.styleable.ApertureView_background_color, 0xFFFFFFFF);    array.recycle();    mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);    mPaint.setAntiAlias(true);    for (int i = 0; i < 6; i++) {      mPoints[i] = new PointF();    }  }  @Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    super.onMeasure(widthMeasureSpec, heightMeasureSpec);    int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);    int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);    int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);    int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);    int paddX = getPaddingLeft() + getPaddingRight();    int paddY = getPaddingTop() + getPaddingBottom();    //光圈的大小要考慮減去view的padding值    mCircleRadius = widthSpecSize - paddX < heightSpecSize - paddY ? (widthSpecSize - paddX) / 2        : (heightSpecSize - paddY) / 2;    //對布局參數為wrap_content時的處理    if (widthSpecMode == MeasureSpec.AT_MOST        && heightSpecMode == MeasureSpec.AT_MOST) {      setMeasuredDimension(WIDTH, HEIGHT);      mCircleRadius = (WIDTH - paddX) / 2;    } else if (widthSpecMode == MeasureSpec.AT_MOST) {      setMeasuredDimension(WIDTH, heightSpecSize);      mCircleRadius = WIDTH - paddX < heightSpecSize - paddY ? (WIDTH - paddX) / 2          : (heightSpecSize - paddY) / 2;    } else if (heightSpecMode == MeasureSpec.AT_MOST) {      setMeasuredDimension(widthSpecSize, HEIGHT);      mCircleRadius = widthSpecSize - paddX < HEIGHT - paddY ? (widthSpecSize - paddX) / 2          : (HEIGHT - paddY) / 2;    }    if (mCircleRadius < 1) {      mCircleRadius = 1;    }    //measure之后才能知道所需要繪制的光圈大小    mPath = new Path();    mPath.addCircle(0, 0, mCircleRadius, Path.Direction.CW);    createBlade();  }  @Override  public void onDraw(Canvas canvas) {    canvas.save();    calculatePoints();    //先把canbvas平移到view的中間    canvas.translate(getWidth() / 2, getHeight() / 2);    //讓光圈的葉片整體旋轉,更加貼合實際    canvas.rotate(ROTATE_ANGLE * (mCurrentApert - mMinApert) / (mMaxApert - mMinApert));    canvas.clipPath(mPath);    canvas.drawColor(mBackgroundColor);    for (int i = 0; i < 6; i++) {      canvas.save();      canvas.translate(mPoints[i].x, mPoints[i].y);      canvas.rotate(-i * 60);      canvas.drawBitmap(mBlade, 0, 0, mPaint);      canvas.restore();    }    canvas.restore();  }  @Override  public boolean onTouchEvent(MotionEvent event) {    if (event.getPointerCount() > 1) {      return false;    }    switch (event.getAction()) {    case MotionEvent.ACTION_DOWN:      mPrevX = event.getX();      mPrevY = event.getY();      break;    case MotionEvent.ACTION_MOVE:      float diffx = Math.abs((event.getX() - mPrevX));      float diffy = Math.abs((event.getY() - mPrevY));      if (diffy > diffx) { // 豎直方向的滑動        float diff = (float) Math.sqrt(diffx * diffx + diffy * diffy)            / mCircleRadius * mMaxApert;        if (event.getY() > mPrevY) { //判斷方向          setCurrentApert(mCurrentApert - diff);        } else {          setCurrentApert(mCurrentApert + diff);        }        mPrevX = event.getX();        mPrevY = event.getY();      }      break;    default:      break;    }    return true;  }  private void calculatePoints() {    if (mCircleRadius - mSpace <= 0) {      Log.e(TAG, "the size of view is too small and Space is too large");      return;    }    //mCircleRadius - mSpace可以保證內嵌六邊形在光圈內    float curRadius = mCurrentApert / mMaxApert * (mCircleRadius - mSpace);    //利用對稱關系,減少計算    mPoints[0].x = curRadius / 2;    mPoints[0].y = -curRadius * COS_30;    mPoints[1].x = -mPoints[0].x;    mPoints[1].y = mPoints[0].y;    mPoints[2].x = -curRadius;    mPoints[2].y = 0;    mPoints[3].x = mPoints[1].x;    mPoints[3].y = -mPoints[1].y;    mPoints[4].x = -mPoints[3].x;    mPoints[4].y = mPoints[3].y;    mPoints[5].x = curRadius;    mPoints[5].y = 0;  }  //創建光圈葉片,讓美工MM提供更好  private void createBlade() {    mBlade = Bitmap.createBitmap(mCircleRadius,        (int) (mCircleRadius * 2 * COS_30), Config.ARGB_8888);    Path path = new Path();    Canvas canvas = new Canvas(mBlade);    path.moveTo(mSpace / 2 / COS_30, mSpace);    path.lineTo(mBlade.getWidth(), mBlade.getHeight());    path.lineTo(mBlade.getWidth(), mSpace);    path.close();    canvas.clipPath(path);    canvas.drawColor(mBladeColor);  }  /**   * 設置光圈片的顏色   * @param bladeColor   */  public void setBladeColor(int bladeColor) {    mBladeColor = bladeColor;  }  /**   * 設置光圈背景色   */  public void setBackgroundColor(int backgroundColor) {    mBackgroundColor = backgroundColor;  }  /**   * 設置光圈片之間的間隔   * @param space   */  public void setSpace(int space) {    mSpace = space;  }  /**   * 設置光圈最大值   * @param maxApert   */  public void setMaxApert(float maxApert) {    mMaxApert = maxApert;  }  /**   * 設置光圈最小值   * @param mMinApert   */  public void setMinApert(float mMinApert) {    this.mMinApert = mMinApert;  }  public float getCurrentApert() {    return mCurrentApert;  }  public void setCurrentApert(float currentApert) {    if (currentApert > mMaxApert) {      currentApert = mMaxApert;    }    if (currentApert < mMinApert) {      currentApert = mMinApert;    }    if (mCurrentApert == currentApert) {      return;    }    mCurrentApert = currentApert;    invalidate();    if (mApertureChanged != null) {      mApertureChanged.onApertureChanged(currentApert);    }  }  /**   * 設置光圈值變動的監聽   * @param listener   */  public void setApertureChangedListener(ApertureChanged listener) {    mApertureChanged = listener;  }}

自定義屬性的xml: 

<?xml version="1.0" encoding="utf-8"?><resources>  <declare-styleable name="ApertureView">    <attr name="blade_color" format="color" />    <attr name="background_color" format="color" />    <attr name="blade_space" format="dimension" />  </declare-styleable></resources>

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 瑞丽市| 中江县| 奉节县| 江安县| 华池县| 鄂托克旗| 尤溪县| 延安市| 枣阳市| 罗平县| 郧西县| 鄂托克前旗| 额尔古纳市| 堆龙德庆县| 莒南县| 故城县| 黄梅县| 化隆| 五大连池市| 巫溪县| 荔浦县| 三明市| 佳木斯市| 台江县| 罗甸县| 郧西县| 化德县| 吴桥县| 岗巴县| 石泉县| 蓬莱市| 尚志市| 广南县| 大安市| 伽师县| 铜山县| 田林县| 台州市| 灌阳县| 闸北区| 左权县|