Android 自定义View,仿微信视频播放按钮

闲着,尝试实现了新版微信视频播放按钮,使用的是自定义View,先来个简单的效果图。。。真的很简单哈。

由于暂时用不到,加上时间原因,加上实在是没意思,加上……,本控件就没有实现自定义属性,有兴趣的朋友可以自己去添加一下,方法都给你们准备好了。- =

其实这个控件主要步骤

1、画外环的圆

2、画进度的圆或者画三角形播放按钮

其余剩下的都是围绕以上两步准备或者收尾的。

接下来贴主要我们的自定义控件代码,注释很全,我就不过多解释了,请各位看官自己分析,有疑问可以在评论区一起讨论。

package com.lwd.playbutton;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.View.OnClickListener;
/**
 * 仿微信视频播放按钮
 * @author Vitor Lee
 */
public class PlayButton extends View implements OnClickListener {
    /**默认最大角度*/
    private static final int DEFAULT_MAX_ANGLE = 360;
    /**默认最大的进度*/
    private static final int DEFAULT_MAX_PROGRESS=100;
    /**描边宽度*/
    private int mStrokeWidth;
    /**外圆环半径*/
    private int mOutRadius;
    /**内圆半径*/
    private int mInnerRiadius;
    /**控件的宽度*/
    private int mWidth;
    /**控件的高度*/
    private int mHeight;
    /**描边的画笔*/
    private Paint mStrokePaint;
    /**实心画笔*/
    private Paint mFillPaint;
    /**进度圆的*/
    private RectF mProgressOval;
    /**最大进度*/
    private int mMax=DEFAULT_MAX_PROGRESS;
    /**当前进度*/
    private int mProgress;
    /**三角形的路径*/
    private Path mTriangle;
    private ProgressState mCurrentState=ProgressState.PRE_START;

    public PlayButton(Context context) {
        this(context,null);
    }

    public PlayButton(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public PlayButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initParams();
        initAttribute(context, attrs, defStyle);
    }

    private void initParams() {
        mStrokeWidth = (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP, 1, getResources()
                        .getDisplayMetrics());

        //初始化描边的笔
        mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mStrokePaint.setColor(Color.WHITE);
        mStrokePaint.setStyle(Paint.Style.STROKE);
        mStrokePaint.setStrokeWidth(mStrokeWidth);

        //初始化画实心的笔
        mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mFillPaint.setColor(Color.WHITE);
        mFillPaint.setStyle(Paint.Style.FILL);

        setOnClickListener(this);
    }

    private void initAttribute(Context context, AttributeSet attrs, int defStyle) {
        //TODO 增加自定义属性,解析应用自定义属性
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;

        //计算外环的半径 得到控件宽高的最小值作为圆的半径,还要减去掉描边的宽度
        mOutRadius = (Math.min(w, h))/2-mStrokeWidth;
        //计算进度圆的半径,减去两倍描边宽度,作为进度圆和外圆环之间的间隙
        mInnerRiadius =mOutRadius-2*mStrokeWidth;
        //确定进度圆的范围
        mProgressOval = new RectF(mWidth / 2 - mInnerRiadius, mHeight / 2
                - mInnerRiadius, mWidth / 2 + mInnerRiadius, mHeight
                / 2 + mInnerRiadius);

        int triangleHeight = mOutRadius/3;
        //用三个点来确定三角形的位置,这里以外圆环直径的1/3作为三角形的水平方向的高度,
        //水平方向向右做了 1/2高度的偏移,让三角形中心与圆的中心重叠(从视觉上来说是中心了,从科学的角度来讲这里应该不是中心,博主数学基础不扎实。。)
        mTriangle = new Path();
        mTriangle.moveTo(w/2-triangleHeight/2,w/2-triangleHeight);
        mTriangle.lineTo(w/2+triangleHeight+triangleHeight/2,h/2);
        mTriangle.lineTo(w/2-triangleHeight/2,w/2+triangleHeight);
        mTriangle.close();
        //等边三角形
//        mRantange = new Path();
//        float halfOfRantangeHeight = (float) (Math.sqrt(1f/27*Math.pow(mOutRadius*2,2)));
//        Log.e("xxx","mOutRadius/3="+mOutRadius/3+" ,halfOfRantangeHeight="+halfOfRantangeHeight);
//        mRantange.moveTo(w/2-mOutRadius/6,h/2-halfOfRantangeHeight);
//        mRantange.lineTo(w/2+mOutRadius/3+mOutRadius/6,h/2);
//        mRantange.lineTo(w/2-mOutRadius/6,h/2+halfOfRantangeHeight);
//        mRantange.close();

    }

    @Override
    protected void onDraw(Canvas canvas) {
        //绘制外圆环
        canvas.drawCircle(mWidth/2,mHeight/2,mOutRadius,mStrokePaint);
        if (mCurrentState==ProgressState.RUNNING) {//运行状态,绘制进度圆
            canvas.drawArc(mProgressOval,-90,(mProgress*1f/mMax*DEFAULT_MAX_ANGLE),true,mFillPaint);
        }else{//非运行状态画三角形
            canvas.drawPath(mTriangle,mStrokePaint);
        }
    }

    @Override
    public void onClick(View v) {
        switch (mCurrentState) {
        case PRE_START:
            if (listener != null) {
                listener.onStart();
            }
            mCurrentState = ProgressState.RUNNING;
            break;
        case RUNNING:
            if (listener != null) {
                listener.onPause(mProgress * 100 / mMax);
            }
            mCurrentState = ProgressState.PAUSE;
            invalidate();
            break;
        case PAUSE:
            if (listener != null) {
                listener.onStart();
            }
            mCurrentState = ProgressState.RUNNING;
            invalidate();
            break;
        case COMPLETELY:
            if (listener!=null) {
                listener.onCompletedClick();
            }
            break;
        }
    }

    private OnProgressClickListener listener;

    /**
     * 设置最大值
     * @param max 最大值
     */
    public void setMax(int max){
        mMax=max;
    }

    /**
     * 设置当前进度
     * @param progress 当前进度
     */
    public void setProgress(int progress){
        mProgress=progress;
        if (mCurrentState!=ProgressState.RUNNING) {
            mCurrentState=ProgressState.RUNNING;
        }
        if (mProgress>=mMax) {
            mCurrentState=ProgressState.COMPLETELY;
            if (listener!=null) {//进度圆完成回调
                listener.onCompletely();
            }
        }
        invalidate();
    }

    /**
     * 设置监听事件
     * @param l 监听器
     */
    public void setOnProgressClickListener(OnProgressClickListener l) {
        this.listener = l;
    }

    /**
     * 这里提供了四个回调方法,比较多,可能只用到其中几个,
     * 所以采用了抽象类来实现,除了必要的开始操作以外,
     * 其他的操作用户需要哪个方法自己复写就行了。
     */
    public static abstract class OnProgressClickListener {
        /** 开始 */
        public abstract void onStart();

        /** 暂停 */
        public void onPause(int percent){};

        /** 结束 */
        public void onCompletely(){};

        /** 完成后点击 */
        public void onCompletedClick(){};
    }

    /**控件状态*/
    public enum ProgressState{
        /**开始之前*/
        PRE_START,
        /**运行*/
        RUNNING,
        /**暂停*/
        PAUSE,
        /**完成*/
        COMPLETELY;
    }

}

接下来我们说说怎么使用,现在xml中定义我们的自定义控件。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}"
    android:background="@android:color/black" >

    <com.lwd.playbutton.PlayButton
        android:id="@+id/buffer_button"
        android:layout_width="50dp"
        android:layout_height="50dp"
        />

</RelativeLayout>

然后我们在Activity中模拟一下缓冲视频,并且播放的操作。

package com.lwd.playbutton;

import com.lwd.bufferbutton.R;
import com.lwd.playbutton.PlayButton.OnProgressClickListener;

import android.app.Activity;
import android.os.Bundle;
import android.os.SystemClock;
import android.widget.Toast;
/**
 * 模拟视频缓冲的activity
 * @author Vitor Lee
 */
public class MainActivity extends Activity {

    private static final int DEFAULT_MAX_VALUE = 100;
    private int mProgress = 0;
    private PlayButton mProgressView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mProgressView = (PlayButton) findViewById(R.id.buffer_button);
        mProgressView.setOnProgressClickListener(getProgressClickListener());
        mProgressView.setMax(DEFAULT_MAX_VALUE);
    }

    private OnProgressClickListener getProgressClickListener() {
        return new OnProgressClickListener() {

            private Thread mDownloadThread;
            private boolean isStop;

            @Override
            public void onStart() {//模拟下载
                if (mDownloadThread==null) {
                    mDownloadThread = new Thread() {
                        @Override
                        public void run() {
                            while (true) {
                                if (!isStop) {
                                    runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            mProgressView.setProgress(mProgress);
                                            mProgress++;
                                        }
                                    });
                                    if (mProgress==DEFAULT_MAX_VALUE) {
                                        break;
                                    }
                                }
                                SystemClock.sleep(100);
                            }
                        }
                    };
                    mDownloadThread.start();
                }
                isStop=false;
            }

            @Override
            public void onPause(int percent) {//暂停
                isStop=true;
            }

            @Override
            public void onCompletely() {
                Toast.makeText(MainActivity.this, "完成", 1).show();
            }

            @Override
            public void onCompletedClick() {//缓冲完成之后点击播放
                Toast.makeText(MainActivity.this, "播放", 1).show();
            }

        };
    }
}
时间: 2024-08-04 03:39:20

Android 自定义View,仿微信视频播放按钮的相关文章

Android自定义View——仿vivo i管家病毒扫描动画效果

技术是永无止境的,如果真的爱技术,那就勇敢的坚持下去.我很喜欢这句话,当我在遇到问题的时候.当我觉得代码枯燥的时候,我就会问自己,到底是不是真的热爱技术,这个时候,我心里总是起着波澜,我的答案是肯定的,我深深的爱着这门技术. 今天我们继续聊聊Android的自定义View系列.先看看效果吧: 这个是我手机杀毒软件的一个动画效果,类似于雷达搜索,所以用途还是很广泛的,特别是先了解一下这里的具体逻辑和写法,对技术的进步一定很有用. 先简单的分析一下这里的元素,主要有四个圆.一个扇形.还有八条虚线.当

Android自定义View——圆形进度条式按钮

介绍 今天上班的时候有个哥们问我怎么去实现一个按钮式的进度条,先来看看他需要实现的效果图. 和普通的圆形进度条类似,只是中间的地方有两个状态表示,未开始,暂停状态.而且他说圆形进度的功能已经实现了.那么我们只需要对中间的两个状态做处理就行了. 先来看看实现的效果图: 上面说了我们只需要处理中间状态的变化就可以了,对于进度的处理直接使用了弘洋文章中实现: http://blog.csdn.net/lmj623565791/article/details/43371299 下面开始具体实现. 具体实

【Android自定义View实战】之仿百度加载动画,一种优雅的Loading方式

转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53470872 本文出自[DylanAndroid的博客] Android自定义View实战之仿百度加载动画一种优雅的Loading方式 第一个仿百度加载动画用ObjectAnimator属性动画操作ImageView的属性方法实现 第二个仿百度加载动画第二种实现方式用ValueAnimator原生的ondraw方法实现 第三个扔球动画-水平旋转动画 第四个扔球动画-垂直旋转动

android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索

我们的手机通讯录一般都有这样的效果,如下图: OK,这种效果大家都见得多了,基本上所有的Android手机通讯录都有这样的效果.那我们今天就来看看这个效果该怎么实现. 一.概述 1.页面功能分析 整体上来说,左边是一个ListView,右边是一个自定义View,但是左边的ListView和我们平常使用的ListView还有一点点不同,就是在ListView中我对所有的联系人进行了分组,那么这种效果的实现最常见的就是两种思路: 1.使用ExpandableListView来实现这种分组效果 2.使

android自定义View之(六)------高仿华为荣耀3C的圆形刻度比例图(ShowPercentView)

为什么写这篇文章: 显示当前的容量所占的比例,表现当前计划的进度,一般都会采用百分比的方式,而图形显示,以其一目了然的直观性和赏心悦目的美观形成为了我们的当然的首选. 在图形表示百分比的方法中,我们有用画圆的圆形进度条的方法<<android自定义View之(二)------简单进度条显示样例篇>>,也有用画弧形的进度条的方法<<android自定义View之(三)------视频音量调控样例>>,今天看到华为荣耀3C的一个界面: 个人觉得这个表示比例的圆形

Android 自定义View合集

自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/Mr-XiaoLiang 自定义控件三部曲 http://blog.csdn.net/harvic880925?viewmode=contents Android 从0开始自定义控件之View基础知识与概念 http://blog.csdn.net/airsaid/article/details/5

Android 自定义EditText输入框 带清空按钮

总结  Android 自定义EditText输入框 带清空按钮 当用户输入字符后  EditText会自动在输入框的内部右侧出现删除按钮 重写EditText达到简化布局的效果 效果图: 继承EditText package com.example.myedittexttest; import android.content.Context; import android.graphics.Rect; import android.graphics.drawable.Drawable; imp

【Android自定义View实战】之超简单SearchView

[Android自定义View实战]之超简单SearchView 在Android开发中我们经常会用到搜索框,而系统提供的又不尽完美.所以自定义一个比较简单的SearchView. 效果图 实现代码 package cn.bluemobi.dylan.searchview; import android.content.Context; import android.text.Editable; import android.text.TextWatcher; import android.ut

Android自定义View,你必须知道的几点

为什么我们觉得自定义View是学习Android的一道坎? 为什么那么多Android大神却认为自定义View又是如此的简单? 为什么google随便定义一个View都是上千行的代码? 以上这些问题,相信学Android的同学或多或少都有过这样的疑问. 那么,看完此文,希望对你们的疑惑有所帮助. 回到主题,自定义View ,需要掌握的几个点是什么呢? 我们先把自定义View细分一下,分为两种 1) 自定义ViewGroup 2) 自定义View 其实ViewGroup最终还是继承之View,当然