안 드 로 이 드 유 틸 리 티 컨트롤 사용자 정의 리 얼 카메라 조리개 보기
한 쌍 촬영 휴대 전화의 큰 조리개 조작 인터페이스 에 조리개 아이콘 이 있어 조리개 조절 시의 실제 효 과 를 모 의 할 수 있 고 느낌 이 좋아 서 이 효 과 를 실현 하려 고 한다.지금 나의 실현 방법 을 모두 에 게 기여 하고 있다.만약 너희 회사 도 더 블 촬영 휴대 전 화 를 만 들 려 고 한다 면? ̄┰ ̄*)
먼저 바 이 두 가 조리개 사진 을 살 펴 보면 그 관건 은 서로 다른 조리개 값 을 계산 할 때 각 조리개 의 위 치 를 계산 하 는 것 임 을 알 수 있다.계산 이 간편 하기 위해 저 는 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>
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.