Android自定义View(四)——仿Android5.0波纹效果

项目源码比较简单,直接看帖的代码就可以了。

说实话,我是真没有去看RippleView的源码,只是从表面看到它的效果,所以产生了一点思路,所以功能很有局限性,而且用起来也比较复杂,大家且看且喷就好^_^。

大致的思路就是在需要波纹效果的视图上叠加一层View,在下层View需要触发波纹效果时,绘制一个从中心扩散的圆,或从四周往中心收缩的圆,只要控制好透明度和颜色还有绘制频率,即可仿效出RippleView的效果。

下面贴出代码:

package com.ykb.json.customview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;

/**
 * com.ykb.json.customview
 * 描述 :简单的水波视图
 * 作者 : ykb
 * 时间 : 15/8/12.
 */
public class WaveView extends TextView
{
    private String TAG = getClass().getSimpleName();
    /**
     * 延迟重绘的时间 ms
     */
    private static final long DRAW_DELAY_MILLS = 15;
    /**
     * 半径的增量
     */
    private static final long RADIUS_INCREMENT_BLOCK = 50;

    /**
     * 波纹模式 -扩散
     */
    public static final int WAVE_MOD_SPREAD = 1;
    /**
     * 波纹模式 -收缩
     */
    public static final int WAVE_MOD_SHRINK = WAVE_MOD_SPREAD+1;
    /**
     * 防止多次加载
      */
    private boolean loadOnce;
    /**
     * 画笔
     */
    private Paint mPaint;
    /**
     * 屏幕像素密度
     */
    private float density;
    /**
     * 占据宽度
     */
    private int width;
    /**
     * 占据高度
     */
    private int height;
    /**
     * 波纹颜色
     */
    private int waveColor = Color.LTGRAY;
    /**
     * 波纹透明度
     */
    private int waveAlph =255;
    /**
     * 波纹渲染半径
     */
    private int radius;
    /**
     * 是否绘制
     */
    private boolean needDraw;
    /**
     * 是否回调最后的波纹颜色
     */
    private boolean changeColor;
    /**
     * 波纹模式 {@link #WAVE_MOD_SHRINK}收缩,{@link #WAVE_MOD_SPREAD}扩散
     */
    private int mode=WAVE_MOD_SPREAD;
    /**
     * 波纹绘制完成后的回调
     */
    private OnWaveCompleteListener callback;
    /**
     * 圆心的横坐标
     */
    private int centerX;
    /**
     * 圆心纵坐标
     */
    private int centerY;
    /**
     * 是否响应touch事件
     */
    private boolean repTouch;


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

    public WaveView(Context context, AttributeSet set)
    {
        this(context, set, 0);

    }

    public WaveView(Context context, AttributeSet set, int defaultStyle)
    {
        super(context, set, defaultStyle);
    }
    /**
     * 设置是否响应touch事件
     */
    public void setRepTouch(boolean repTouch)
    {
        this.repTouch = repTouch;
    }
    /**
     * 设置是否需要返回颜色
     * @param changeColor
     */
    public void setChangeColor(boolean changeColor)
    {
        this.changeColor = changeColor;
    }

    /**
     * 设置波纹展现模式
     * @param mode {@link #WAVE_MOD_SHRINK}收缩,{@link #WAVE_MOD_SPREAD}扩散
     */
    public void setMode(int mode)
    {
        this.mode = mode;
    }
    /**
     * 开始绘制
     */
    public void startDraw(){
        if(!repTouch){
            centerX=width/2;
            centerY=height/2;
        }
        startInvalidate();
    }
    /**
     * 开始绘制
     */
    private void startInvalidate(){
        needDraw=true;
        resetPaint();
        switch (mode){
            case WAVE_MOD_SHRINK:
                radius=width;
                break;
            case WAVE_MOD_SPREAD:
                radius=0;
                break;
        }
        invalidate();
    }
    /**
     * 设置是否可以画
     *
     * @param needDraw
     */
    public void setNeedDraw(boolean needDraw)
    {
        this.needDraw = needDraw;
    }

    /**
     * 设置波纹透明度
     *
     * @param waveAlph
     */
    public void setWaveAlph(int waveAlph)
    {
        this.waveAlph = waveAlph;
    }

    /**
     * 设置波纹颜色
     *
     * @param waveColor
     */
    public void setWaveColor(int waveColor)
    {
        this.waveColor = waveColor;
    }

    /**
     * 设置波浪完成后的回调接口
     * @param callback
     */
    public void setCallback(OnWaveCompleteListener callback)
    {
        this.callback = callback;
    }
    /**
     * 初始化
     */
    private void onLayoutInit()
    {
        density = getResources().getDisplayMetrics().density;
        width = getWidth();
        height = getHeight();
        mPaint = new Paint();
        resetPaint();
        loadOnce = !loadOnce;
    }

    /**
     * 画笔重置
     */
    private void resetPaint()
    {
        mPaint.reset();
        mPaint.setAntiAlias(true);
    }

    /**
     * 清除画布
     * @param canvas
     */
    private void clearCanvas(Canvas canvas)
    {
        canvas.restore();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom)
    {
        super.onLayout(changed, left, top, right, bottom);
        if (changed && !loadOnce) {
            onLayoutInit();
        }
    }

    @Override
    public boolean onTouchEvent( MotionEvent event)
    {
        if(!repTouch)
            return  super.onTouchEvent(event);

        int action=event.getAction();
        Log.e("onTouch,action : "+action);
        if(action==MotionEvent.ACTION_UP){
            centerX=(int)event.getX();
            centerY=(int)event.getY();
            startInvalidate();
        }

        return  super.onTouchEvent(event);
    }

    @Override
    public void draw(Canvas canvas)
    {
        super.draw(canvas);
        boolean end=false;
        switch (mode){
            case WAVE_MOD_SHRINK:
                if(radius<=0)
                    end=true;
                break;
            case WAVE_MOD_SPREAD:
                if(radius >= width / 2)
                    end=true;
                break;
        }

        if (!needDraw||end) {
            if(null!=callback&&needDraw&&changeColor) {
                callback.onWaveComplete(waveColor);
            }
            clearCanvas(canvas);
            return;
        }

        if(radius==(mode==WAVE_MOD_SPREAD?0:width))
            canvas.save();

        mPaint.setColor(waveColor);
        mPaint.setAlpha(waveAlph);
        canvas.drawCircle(centerX, centerY, radius, mPaint);
        radius += (mode==WAVE_MOD_SPREAD?RADIUS_INCREMENT_BLOCK:-RADIUS_INCREMENT_BLOCK);
        postInvalidateDelayed(DRAW_DELAY_MILLS);
    }
    /**波纹绘制完成的回调接口**/
    public interface OnWaveCompleteListener{
        public void onWaveComplete(int color);
    }
}

代码就是这么简单,在使用的时候只需按自己的需求叠加到相应的控件上,然后设置好相关属性,调用startDraw方法即可。

-布局使用如下

<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/dimen_40"
        android:layout_marginLeft="@dimen/dimen_40"
        android:layout_marginRight="@dimen/dimen_40"
        android:layout_marginTop="@dimen/dimen_40">
        <Button
            android:id="@+id/btn_login_bg"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/title_bg1"
            />
        <com.ykb.json.customview.WaveView
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:id="@+id/layout_login"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </com.ykb.json.customview.WaveView>
        <Button
            android:id="@+id/btn_login"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@null"
            android:text="登  录"
            android:textColor="@color/white"
            android:textSize="@dimen/dimen_18"/>

    </RelativeLayout>

-代码使用如下

private void initUI() {
    layout_login=(WaveView)findViewById(R.id.layout_login);
    layout_login.setCallback(this);
    layout_login.setMode(WaveView.WAVE_MOD_SHRINK);
    layout_login.setChangeColor(true);
}
@Override
public void onClick(View v) {
    layout_login.startDraw();
}   

@Override
public void onWaveComplete(int color){
    btn_login_bg.setBackgroundColor(color);
}

写完这篇博客后我就去看看RippleView的实现原理,我知道这个波纹效果肯定差它差的太远,但是依然希望有大神提供更好的思路,给我们这些初学者学习更多的自定义View知识。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个已经集成了聊天发送文字表情和语音功能的输入模块 无需再写任何代码 自己写的 5分绝对值 使用方法: 第一步:文件怎么放 把三个文件夹里的东西分别放在制定的地方就行 第二步:布局到我的activity中 把它当成一个普通的view就好 放在你想放的位置 以下是我在自己项目里放的位置 放在布局的最低端 <com example defined SendMassageRelativeLayout android:id "@+id rl bottom" android:layout width "fill parent" android:layout height "wrap content" android:layout alignParentBottom "true" android:background "#aaa" > 第三步:怎么用该控件实现发送文字表情和语音 首先 在activity中获得该SendMassageRelativeLayout 并设置两个参数 第一个是语音的录音要放的文件夹路径(文件夹要在activity中建好) 通过SendMassageRelativeLayout对象 SetRootPath String path 设置 第二个是对象SendMessageListener对象 这个对象是一个自定义的接口 要在activity中实现 通过SendMassageRelativeLayout对象 SetSendMessageListener this ;设置 其中this是因为该activity实现了接口 也可以自定义一个类来实现接口 然后在SendMessageListener接口的两个函数中实现语音与 普通文字表情的发送代码就行了 public void getAndSendMessage String str 是发送文字与表情的 点击发送时会调用这个方法 表情已经转变为字符串 str就是要发送的内容 至于要发到哪怎么发自己编写 显示的时候还要解析一下 分离出表情 下面说解析过程 文件中提供的一个类ExpressionUtil java就是解析的工具类 只需要在设置显示的TextView内容时用以下代码就行 String message; 消息具体内容 String zhengze "f0[0 9]{2}|f10[0 7]"; 正则表达式 用 try { SpannableString spannableString ExpressionUtil getExpressionString context message zhengze ; myTextView setText spannableString ; } catch NumberFormatException e { e printStackTrace ; } catch SecurityException e { e printStackTrace ; } catch IllegalArgumentException e { e printStackTrace ; } 语音的发送 语音发送的时候会执行实现接口中的public void getAndSendVoice String path int time 方法path是录制的语音在本地的绝对路径 time是语音的时长 秒为单位 至于接下来是要通过网络发送出去还是播放 自己实现ok了 总之很简单方便 表情输入 文字输入 录音 以及这些功能的切换都已经在内部实现 不需要任何代码 ">这是一个已经集成了聊天发送文字表情和语音功能的输入模块 无需再写任何代码 自己写的 5分绝对值 使用方法: 第一步:文件怎么放 把三个文件夹里的东西分别放在制定的地方就行 第二步:布局到我的activity中 [更多]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值