Android 书写拍照与录制小视频按钮的Fragment
单位要做个录制视频哈拍照的效果,无奈,没有Android 开发经验,不知道去哪里找合适工控件,最主要是不知道这个控件应该叫什么名字
在个人无奈的情况下 写个个动系,希望对要写控件 或者说是要写 动画的 朋友有所帮助把
在开始前说点没用的:
1 这个控件设计了 Android 动画:帧动画,和属性动画 两种 和和动画插值器【AnimationDrawable ,ObjectAnimator, Interpolator,】附加的其他【PropertyValuesHolder】
2 涉及 android 的 多进程的编程 【Handler,Runnable】
3 涉及 Android 绘画对象 【Drawable】
4 Canvers 的简单用法
你看看你上面的说明在代码中都有体现 这里简单给大家介绍一下 可跳过
1 AnimationDrawable 为Android的帧动画的主要对象与渐变动画都 属于传动动画, 但是 Interpolator 插值器,有六种 加速,减速,加速减速,动画回弹,正弦变速,匀速 AccelerateDecelerateInterpolator,AccelerateInterpolator,DecelerateInterpolator,BounceInterpolator,CycleInterpolator,LinearInterpolator 以上插值器 都可以用作属性动画 一定要记得
2 还有一个是就 窜通动画 TranslateAnimation ,Scale..., Rotate .....,Alpha.... 理解了就理解他们之间的关系就简单了
3 帮大家理解一下,2 中的渐变豆花为传统动画 他只改变其形 但是不改变其实质 ,TranslateAnimation 初始化后 设置其插值器,完后start 就OK了
属相动画 改变其形同时也改变其质。
开始吧 打字真的手指头通呀:
一:
创建一个Fragment
ButtonFragment.xml
代码如下:
<?xml version="1.0" encoding="utf-8"?>
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context=".ButtonFragment">
android:id="@+id/frame_loyout_container"
android:layout_width="90dp"
android:layout_height="90dp">
android:id="@+id/btn_fragment_bgImg"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:background="#cccccc" />
android:id="@+id/btn_fragment_forImg"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:background="#102323" />
说明一下,这里的两层布局 因为我尝试了一层 他会出现无法改变布局大小的现象,感兴趣的可以试一下
后台代码开始处理计划目标, 这里我将注释全部添加到代码上方便 理解
package com.app.yispace.app.anmationdemo;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import java.lang.reflect.Type;
/**
* A simple {@link Fragment} subclass.
* Activities that contain this fragment must implement the
* {@link ButtonFragment.OnFragmentInteractionListener} interface
* to handle interaction events.
* Use the {@link ButtonFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class ButtonFragment extends Fragment {
private OnFragmentInteractionListener mListener;
// 这是背景图片 要绘制圆形的imageView
ImageView bgimg;
//这是大家可以见见的中间的ImageView
ImageView forimg;
/// 这里是容器空间包含了俩个ImageView
FrameLayout containerframe;
/// 我们自己定义的动画对象
YSAnimationDrawable myAnimationDrawable;
String TAG = "LazyCoder";
/// 这是我们处理事件的外界接口状态所
TONCHSTATE tonchstate = TONCHSTATE.TONCH;
//这是动画 结束但手为松开的 定时器
Handler handler = new Handler();
// 则是处理执行动画的时间
int timeLenght = 10;
public ButtonFragment() {
// Required empty public constructor
}
public static ButtonFragment newInstance() {
ButtonFragment fragment = new ButtonFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
}
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_button, container, false);
;
bgimg = view.findViewById(R.id.btn_fragment_bgImg);
forimg = view.findViewById(R.id.btn_fragment_forImg);
containerframe = view.findViewById(R.id.frame_loyout_container);
// 上面的就不会了
//这个方法是舒适化 动画的
initanimationDrawable();
// 设置点击事件 的两个监听
containerframe.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://0
tonchstate = TONCHSTATE.TONCH;//改变状态信息
StartAnimation(); // 设置空间的属相动画,大小
break;
case MotionEvent.ACTION_UP://1
if (tonchstate != TONCHSTATE.NULL) { // 这里要 因为有一个定时器,在处理我们的这个状态所以要判断一下
myAnimationDrawable.stop(); // 停止背景动画。也就是帧动画 因为,帧动画的开始是长按
EndAnimation();// 设置空间的属相动画,大小
if (mListener != null) {
mListener.StopAtion(tonchstate);
}
tonchstate = TONCHSTATE.NULL;
}
break;
case MotionEvent.ACTION_MOVE://2
break;
}
return false;
}
});
// 这是长按
containerframe.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
myAnimationDrawable.start();//开始帧动画
tonchstate = TONCHSTATE.LONGTONCH;// 改变状态
if (mListener != null)
mListener.StartLongTonch(); //这里就是给外界提供的接口 用于处理
handler.postDelayed(new Runnable() {// 这里就是处理 长时间按住后不放开的处理
@Override
public void run() {
if (tonchstate != TONCHSTATE.NULL) { // 这里和上面说的那个一样 因为有时间为结束就只想了这个事件状态
myAnimationDrawable.stop();
EndAnimation();
tonchstate = TONCHSTATE.NULL;
if (mListener != null) {
mListener.StopAtion(tonchstate);
}
}
}
}, timeLenght * 1000);
return false;
}
});
return view;
}
private void EndAnimation() {
// s属相动画 修改 放缩 X轴
ObjectAnimator objectAnimatorX = ObjectAnimator.ofFloat(forimg,
"scaleX", 0.5f, 1f).setDuration(500);
objectAnimatorX.setInterpolator(new AccelerateInterpolator());
objectAnimatorX.start();
// s属相动画 修改 放缩 Y轴
ObjectAnimator ojectAnimatorY = ObjectAnimator.ofFloat(forimg, "scaleY",
0.5f, 1f).setDuration(500);
ojectAnimatorY.setInterpolator(new AccelerateInterpolator());
ojectAnimatorY.start();
/// 这个是 另一种写法 哈哈哈
PropertyValuesHolder propertyValuesHolderscaleP_X = PropertyValuesHolder
.ofFloat
("scaleX", 1.3f, 1f);
PropertyValuesHolder propertyValuesHolderscaleP_Y = PropertyValuesHolder
.ofFloat
("scaleY", 1.3f, 1f);
ObjectAnimator.ofPropertyValuesHolder
(bgimg, propertyValuesHolderscaleP_X, propertyValuesHolderscaleP_Y)
.setDuration(500).start();
}
private void StartAnimation() {
PropertyValuesHolder propertyValuesHolderscaleX = PropertyValuesHolder.ofFloat
("scaleX", 1f, 0.5f);
PropertyValuesHolder propertyValuesHolderscale = PropertyValuesHolder.ofFloat
("scaleY", 1f, 0.5f);
ObjectAnimator.ofPropertyValuesHolder
(forimg, propertyValuesHolderscaleX, propertyValuesHolderscale)
.setDuration(500).start();
PropertyValuesHolder propertyValuesHolderscalePX = PropertyValuesHolder
.ofFloat
("scaleX", 1f, 1.3f);
PropertyValuesHolder propertyValuesHolderscalePY = PropertyValuesHolder
.ofFloat
("scaleY", 1f, 1.3f);
ObjectAnimator.ofPropertyValuesHolder
(bgimg, propertyValuesHolderscalePX, propertyValuesHolderscalePY)
.setDuration(500).start();
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
private void initanimationDrawable() {
myAnimationDrawable = new YSAnimationDrawable(timeLenght, Paint.Style.STROKE);
bgimg.setBackground(myAnimationDrawable.build().getAnimationDrawable());
forimg.setBackground(new ForDrawable("#ffffff"));
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
// throw new RuntimeException(context.toString()
// + " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public void setmListener(OnFragmentInteractionListener mListener) {
this.mListener = mListener;
}
///状态属性的 枚举
public enum TONCHSTATE {
LONGTONCH,
TONCH,
NULL,
}
public interface OnFragmentInteractionListener {
void StopAtion(TONCHSTATE state);
void StartLongTonch();
}
// 自定义的动画容器
class YSAnimationDrawable {
// 这个是针动画
AnimationDrawable animationDrawable = new AnimationDrawable();
// 检测属性
boolean isBuild = false;
Paint.Style style;
int DEPLEYTIME = 25;
int TimeLength;
int angle;
int strokeWidth = 5;
String bgRGB = "#6f6f71";
String corcleLineRGB = "#00ff00";
public YSAnimationDrawable(int timeLength, Paint.Style style) {
TimeLength = timeLength;
this.style = style;
}
public YSAnimationDrawable(int timeLength) {
TimeLength = timeLength;
}
public AnimationDrawable getAnimationDrawable() {
return animationDrawable;
}
public YSAnimationDrawable build() {
setAnimationDrawableCore();
float angle = 360f / (TimeLength * DEPLEYTIME);
float cangile = 0;
int i = 1;
while (true) {
cangile = angle * i;
YsDrawable drawable = new YsDrawable(Math.round
(cangile), bgRGB, corcleLineRGB,
style, strokeWidth);
animationDrawable.addFrame(drawable, 40);
i++;
if (cangile >= 360)
break;
}
isBuild = true;
return this;
}
private void setAnimationDrawableCore() {
animationDrawable.setOneShot(true);
}
public void start() {
if (isBuild == false)
throw new ExceptionInInitializerError("You not Invoke build Function");
animationDrawable.setVisible(true, false);
animationDrawable.start();
}
public void stop() {
animationDrawable.setVisible(true, true);
animationDrawable.stop();
}
}
class YsDrawable extends Drawable {
int sweepleAngle;
Paint paint;
String bgRGB = "#6f6f71";
String corcleLineRGB = "#00ff00";
Paint.Style style;
int strokeWidth;
public YsDrawable(int sweepleAngle, String bgRGB, String corcleLineRGB, Paint.Style style, int strokeWidth) {
this.sweepleAngle = sweepleAngle;
this.bgRGB = bgRGB;
this.corcleLineRGB = corcleLineRGB;
this.style = style;
this.strokeWidth = strokeWidth;
InitParam();
}
public int getSweepleAngle() {
return sweepleAngle;
}
private void InitParam() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(strokeWidth);
paint.setStyle(style);
paint.setColor(Color.parseColor(corcleLineRGB));
paint.setStrokeCap(Paint.Cap.BUTT);
}
/**
* Draw in its bounds (set via setBounds) respecting optional effects such
* as alpha (set via setAlpha) and color filter (set via setColorFilter).
*
* @param canvas The canvas to draw into
*/
@Override
public void draw(@NonNull Canvas canvas) {
int x = canvas.getWidth();
int y = canvas.getHeight();
int minOne = x > y ? y / 2 : x / 2;
Float padding = paint.getStrokeWidth() / 2;
Paint cpaint = new Paint();
cpaint.setAntiAlias(true);
cpaint.setStyle(Paint.Style.FILL);
cpaint.setColor(Color.parseColor(bgRGB));
canvas.drawCircle((float) minOne, (float) minOne, (float) minOne, cpaint);
RectF rectF = new RectF(padding, padding, canvas.getHeight() - paint.getStrokeWidth()
, canvas.getWidth() - paint.getStrokeWidth());
canvas.drawArc(rectF, -90, sweepleAngle, false, paint);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
@SuppressLint("WrongConstant")
@Override
public int getOpacity() {
return 0;
}
}
class ForDrawable extends Drawable {
public ForDrawable(String forRGB) {
this.forRGB = forRGB;
}
public void setForRGB(String forRGB) {
this.forRGB = forRGB;
}
String forRGB = null;
@Override
public void draw(@NonNull Canvas canvas) {
int x = canvas.getWidth() / 2;
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.parseColor(forRGB));
canvas.drawCircle(x, x, x, paint);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
@SuppressLint("WrongConstant")
@Override
public int getOpacity() {
return 0;
}
}
}
以上我感觉需要注释的都给了 有不明白的我可以在给你添加说明
三
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/frame_loyout_name"
android:name="com.app.yispace.app.anmationdemo.ButtonFragment"
>