直接调用系统相机拍照,代码参考如下
/**
* Call system camera to take photo
*/
public void takePhoto() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Log.e(TAG, ex.getMessage(), ex);
}
Log.i(TAG, "takePhoto photoFile : " + photoFile);
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
FILE_PROVIDER_AUTHORITY,
photoFile);
currentPhotoPath = photoFile.getAbsolutePath();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, START_SYSTEM_CAMERA_REQUEST_CODE);
Log.i(TAG, "startActivityForResult START_SYSTEM_CAMERA_REQUEST_CODE");
}
}
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = new File(this.getFilesDir(), "images");
if (!storageDir.exists()) {
storageDir.mkdir();
}
File image = File.createTempFile(
imageFileName, /* prefix */
".bmp", /* suffix */
storageDir /* directory */
);
return image;
}
一个圆形自定义进度条
package com.grab.ui.widget
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.content.res.TypedArray
import android.graphics.*
import android.text.TextPaint
import android.util.AttributeSet
import android.view.View
import android.view.animation.LinearInterpolator
import com.base.utils.DrawUtils
import com.grab.R
import kotlin.math.cos
import kotlin.math.sin
class CircleProgress @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
companion object {
private const val DEFAULT_CENTER_TEXT_SIZE = 16
private const val DEFAULT_OUTSIDE_CIRCLE_WIDTH = 2
private const val DEFAULT_INNER_CIRCLE_WIDTH = 15
private const val DEFAULT_RADIUS = 100
private const val DEFAULT_OUT_COLOR = "#66FFFFFF"
private const val DEFAULT_MID_COLOR = "#66FFFFFF"
private const val DEFAULT_POINT_COLOR = "#FFFFFF"
private const val DEFAULT_TEXT_COLOR = "#FFFFFF"
private const val DEFAULT_START_COLOR = "#FFFFFF"
private const val DEFAULT_OUTSIDE_POINT_RADIUS = 5
private const val DEFAULT_CIRCLE_SPACE = 8
const val PROGRESS_MODE = 0
const val REPEAT_MODE = 1
}
private var mCenterTextSize: Float = DrawUtils.dp2px(context, DEFAULT_CENTER_TEXT_SIZE)
private var mCenterTextColor: Int = Color.parseColor(DEFAULT_TEXT_COLOR)
private var mOutSideCircleWidth: Float = DrawUtils.dp2px(context, DEFAULT_OUTSIDE_CIRCLE_WIDTH)
private var mOutSideCircleColor: Int = Color.parseColor(DEFAULT_OUT_COLOR)
private val mPointColor = Color.parseColor(DEFAULT_POINT_COLOR)
private var mOutSidePointRadius: Float = DrawUtils.dp2px(context, DEFAULT_OUTSIDE_POINT_RADIUS)
private var mRadius: Float = DrawUtils.dp2px(context, DEFAULT_RADIUS)
private var mInnerCircleWidth: Float = DrawUtils.dp2px(context, DEFAULT_INNER_CIRCLE_WIDTH)
private var mInnerCircleStartColor = Color.parseColor(DEFAULT_START_COLOR)
private var mInnerCircleEndColor = Color.parseColor(DEFAULT_MID_COLOR)
private var mCircleSpace = DrawUtils.dp2px(context, DEFAULT_CIRCLE_SPACE)
private var mProgress: Int = 0
private var mCenterX: Float = 0F
private var mCenterY: Float = 0F
private var mOutCircleRadius = 0F
private var mInnerCircleRadius = 0F
private var mProgressText = ""
private var mHintText = ""
private var mTextHeight = 0F
private var mProgressTextWidth = 0F
private var mHintTextWidth = 0F
private var mode = REPEAT_MODE
private var startAngle = 0F
private val repeatAnimator: ValueAnimator by lazy {
ValueAnimator.ofFloat(0F, 360F).apply {
duration = 3000
addUpdateListener {
startAngle = it.animatedValue as Float
postInvalidate()
}
interpolator = LinearInterpolator()
repeatCount = ValueAnimator.INFINITE
}
}
private var progressAnimator: ValueAnimator? = null
private val centerPaint: TextPaint by lazy {
TextPaint().apply {
isAntiAlias = true
flags = Paint.ANTI_ALIAS_FLAG
style = Paint.Style.FILL
typeface = Typeface.DEFAULT_BOLD
textSize = mCenterTextSize
color = mCenterTextColor
mTextHeight = fontMetrics.descent - fontMetrics.ascent
}
}
private val outSideCirclePaint: Paint by lazy {
Paint().apply {
isAntiAlias = true
style = Paint.Style.STROKE
strokeWidth = mOutSideCircleWidth
color = mOutSideCircleColor
}
}
private val outSidePointPaint: Paint by lazy {
Paint().apply {
isAntiAlias = true
style = Paint.Style.FILL
color = mPointColor
}
}
private val innerCirclePaint: Paint by lazy {
Paint().apply {
isAntiAlias = true
style = Paint.Style.STROKE
strokeWidth = mInnerCircleWidth
shader = SweepGradient(
mCenterX,
mCenterY,
intArrayOf(mInnerCircleStartColor, mInnerCircleEndColor, mInnerCircleStartColor),
null
)
}
}
private val mInnerCircleRect: RectF by lazy {
RectF(
mCenterX - mInnerCircleRadius,
mCenterY - mInnerCircleRadius,
mCenterX + mInnerCircleRadius,
mCenterY + mInnerCircleRadius
)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
if (mRadius * 2 > measuredWidth.coerceAtMost(measuredHeight) &&
measuredWidth.coerceAtMost(measuredHeight) > 0
) {
mRadius = measuredWidth.coerceAtMost(measuredHeight).toFloat() / 2
}
mCenterX = (measuredWidth / 2).toFloat()
mCenterY = (measuredHeight / 2).toFloat()
mOutCircleRadius = mRadius - mOutSideCircleWidth
mInnerCircleRadius = mRadius - mOutSideCircleWidth - mInnerCircleWidth - mCircleSpace
}
override fun onDraw(canvas: Canvas?) {
drawRepeatCircle(canvas)
}
private fun drawRepeatCircle(canvas: Canvas?) {
canvas?.run {
// 外圈
drawCircle(mCenterX, mCenterY, mOutCircleRadius, outSideCirclePaint)
// 内圈
drawArc(mInnerCircleRect, startAngle, 360F, true, innerCirclePaint)
// 外圈小圆点
drawCircle(
(mCenterX + sin(startAngle * Math.PI / 180) * mOutCircleRadius).toFloat(),
(mCenterY - cos(startAngle * Math.PI / 180) * mOutCircleRadius).toFloat(),
mOutSidePointRadius,
outSidePointPaint
)
// 进度
drawText(mProgressText, mCenterX - mProgressTextWidth / 2, mCenterY, centerPaint)
// 提示文字
drawText(
mHintText,
mCenterX - mHintTextWidth / 2,
mCenterY + mTextHeight,
centerPaint
)
}
}
fun setProgress(progress: Int) {
mProgress = progress
updateProgress()
}
private fun updateProgress() {
if (progressAnimator != null) {
progressAnimator?.cancel()
}
progressAnimator = ValueAnimator.ofFloat(startAngle, 3.6F * mProgress).apply {
duration = 300
addUpdateListener {
startAngle = it.animatedValue as Float
postInvalidate()
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
if (mProgress == 100) {
startAngle = 0F
}
}
})
interpolator = LinearInterpolator()
}
progressAnimator?.start()
}
fun setProgressText(text: String) {
mProgressText = text
mProgressTextWidth = centerPaint.measureText(mProgressText)
postInvalidate()
}
fun setHintText(text: String) {
mHintText = text
mHintTextWidth = centerPaint.measureText(mHintText)
postInvalidate()
}
fun setMode(mode: Int) {
this.mode = mode
when (mode) {
REPEAT_MODE -> {
repeatAnimator.start()
}
PROGRESS_MODE -> {
repeatAnimator.cancel()
}
}
postInvalidate()
}
init {
initAttrs(context, attrs)
}
private fun initAttrs(context: Context, attrs: AttributeSet?) {
val typeArray: TypedArray =
context.theme.obtainStyledAttributes(attrs, R.styleable.CircleProgress, 0, 0)
mCenterTextSize =
typeArray.getDimension(R.styleable.CircleProgress_centerTextSize, mCenterTextSize)
mCenterTextColor =
typeArray.getColor(R.styleable.CircleProgress_centerTextColor, mCenterTextColor)
mOutSideCircleWidth =
typeArray.getDimension(R.styleable.CircleProgress_outCircleWidth, mOutSideCircleWidth)
mOutSideCircleColor =
typeArray.getColor(R.styleable.CircleProgress_outCircleColor, mOutSideCircleColor)
mOutSidePointRadius =
typeArray.getDimension(R.styleable.CircleProgress_outPointRadius, mOutSidePointRadius)
mRadius = typeArray.getDimension(R.styleable.CircleProgress_progressRadius, mRadius)
mInnerCircleWidth =
typeArray.getDimension(R.styleable.CircleProgress_innerCircleWidth, mInnerCircleWidth)
mInnerCircleStartColor = typeArray.getColor(
R.styleable.CircleProgress_innerCircleStartColor,
mInnerCircleStartColor
)
mInnerCircleEndColor =
typeArray.getColor(R.styleable.CircleProgress_innerCircleEndColor, mInnerCircleEndColor)
typeArray.recycle()
}
}
在xml布局文件中引用
<com.grab.ui.widget.CircleProgress
android:id="@+id/cp_progress"
hintText="@{viewModel.cpHintText}"
mode="@{viewModel.cpMode}"
progress="@{viewModel.cpProgress}"
progressText="@{viewModel.cpProgressText}"
android:layout_width="280dp"
android:layout_height="280dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
app:layout_constraintBottom_toBottomOf="@id/iv_bg"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/iv_bg"
app:progressRadius="130dp" />
一个工具类
/**
* 绘制工具类
*/
object DrawUtils {
private var sDensity = 1.0f
private var sClass: Class<*>? = null
/**
* dip/dp转像素
*
*
* dip或 dp大小
*
* @return 像素值
*/
fun dp2px(context: Context, dp: Int): Float {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), context.resources
.displayMetrics
)
}
fun resetDensity(context: Context?) {
if (context != null && null != context.resources) {
val metrics = context.resources.displayMetrics
sDensity = metrics.density
}
resetNavBarHeight(context)
}
private fun resetNavBarHeight(context: Context?) {
if (context != null) {
val wm =
context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val display = wm.defaultDisplay
// 虚拟键高度
if (sClass == null) {
sClass = Class.forName("android.view.Display")
}
val realSize = Point()
val method =
sClass!!.getMethod("getRealSize", Point::class.java)
method.invoke(display, realSize)
}
}
fun getScreenWidth(context: Context): Int {
val manager = context
.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val outMetrics = DisplayMetrics()
manager.defaultDisplay.getMetrics(outMetrics)
return outMetrics.widthPixels
}
}