안 드 로 이 드 유 틸 리 티 컨트롤 사용자 정의 리 얼 카메라 조리개 보기

11013 단어 Android카메라.View
최근 휴대 전화 업계 에 서 는 듀 얼 카메라 가 유행 하기 시 작 했 고,큰 조리개 기능 도 응용 되 어 생 겨 났 다.큰 조리개 기능 이란 사진 을 후기 에 다시 초점 을 맞 출 수 있 는 것 이다.그 실현 원 리 는 주로 사진 을 찍 는 동안 얻 은 깊이 있 는 사진 과 초점 이 무한 한 이미 지 를 알고리즘 을 통 해 다시 초점 을 맞 추 는 효 과 를 실현 하 는 것 이다. 
한 쌍 촬영 휴대 전화의 큰 조리개 조작 인터페이스 에 조리개 아이콘 이 있어 조리개 조절 시의 실제 효 과 를 모 의 할 수 있 고 느낌 이 좋아 서 이 효 과 를 실현 하려 고 한다.지금 나의 실현 방법 을 모두 에 게 기여 하고 있다.만약 너희 회사 도 더 블 촬영 휴대 전 화 를 만 들 려 고 한다 면? ̄┰ ̄*) 
먼저 바 이 두 가 조리개 사진 을 살 펴 보면 그 관건 은 서로 다른 조리개 값 을 계산 할 때 각 조리개 의 위 치 를 계산 하 는 것 임 을 알 수 있다.계산 이 간편 하기 위해 저 는 6 개의 직 변 엽편 의 조리개 효 과 를 예 로 들 어 실현 합 니 다(다른 형식,예 를 들 어 7 개의 엽편,즉 위치 계산 이 약간 편리 하지 않 습 니 다.일부 원호 의 잎 은 잎 양쪽 의 원호 반지름 을 만족 시 키 기만 하면 된다.왜 원호 반경 이 같 아야 합 니까?자세히 살 펴 보면 인접 한 두 잎 사 귀 사이 가 서로 미 끄 러 지고 똑 같은 일치 거 리 를 유지 해 야 한 다 는 것 을 알 수 있 습 니 다.제 가 증 금 초등학교 기하학 과 에서 만점 을 받 은 경험 에 따 르 면 등 경의 원호 가 좋 은 것 이 라 고 판단 할 수 있 습 니 다.다른 고급 곡선 이 이 효 과 를 실현 할 수 있 는 지 수학자(~9520~*)에 게 물 어보 세 요!다른 부분의 원 리 는 모두 같다.  
제작 효과 도: 

먼저 본 사용자 정의 view 의 주요 내용 을 설명 합 니 다.
 1.이 효과 의 실현 은 바로 조리개 안의 육각형 6 개의 각 에 각각 6 개의 조리개 잎 을 그 리 는 것 이다.
 2.서로 다른 조리개 값 에 따라 내 육각형 의 크기 를 계산 하여 각 육각형 의 정점 위 치 를 계산한다.
 3.디자인 리 프 트.이 방안 은 스스로 코드 로 그 렸 다.잎 사 귀 사이 의 간격 거리 와 각 잎의 각도 가 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>
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기