這個效果作出來之後,真的美極了!放在你的應用中,無疑增添了光彩!java
其實,第一種效果,纔是產品的需求要的效果。第三種效果,是否是很熟悉?支付寶的咻一咻!哈哈,無心中,我就寫出來了。android
1.attrs.xml定義屬性git
<declare-styleable name="WaveView"> <!--圓顏色--> <attr name="wave_color" format="color"/> <!--中心圓圖片半徑--> <attr name="wave_coreImageRadius" format="integer"/> <!--波浪圓之間間距,值越小越窄--> <attr name="wave_width" format="integer"/> </declare-styleable>
2.WaveView的初始化github
/** * 波浪圓圈顏色 */ private int mColor = getResources().getColor(R.color.yellow); /** * 第一個圓圈的半徑(也就是圓形圖片的半徑) */ private int mImageRadius=50; /** * 波浪圓之間間距 */ private int mWidth = 3; /** * 最大寬度 */ private Integer mMaxRadius = 300; /** * 是否正在擴散中 */ private boolean mIsWave = false; // 透明度集合 private List<Integer> mAlphas = new ArrayList<>(); // 擴散圓半徑集合 private List<Integer> mRadius = new ArrayList<>(); private Paint mPaint; public WaveView(Context context) { this(context, null); } public WaveView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public WaveView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WaveView, defStyleAttr, 0); mColor = a.getColor(R.styleable.WaveView_wave_color, mColor); mWidth = a.getInt(R.styleable.WaveView_wave_width, mWidth); mImageRadius = a.getInt(R.styleable.WaveView_wave_coreImageRadius, mImageRadius); a.recycle(); } private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); // mAlphas.add(255); // mRadius.add(0); }
3.重寫onDraw()canvas
@Override
public void onDraw(Canvas canvas) { // 繪製擴散圓 mPaint.setColor(mColor); for (int i = 0; i < mAlphas.size(); i++) { // 設置透明度 Integer alpha = mAlphas.get(i); mPaint.setAlpha(alpha); // 繪製波浪圓 Integer radius = mRadius.get(i); canvas.drawCircle(getWidth() / 2, getHeight() / 2, mImageRadius+radius, mPaint); if (alpha > 0 && mImageRadius+radius < mMaxRadius) { alpha = (int) (255.0F * (1.0F - (mImageRadius+radius) * 1.0f / mMaxRadius)); mAlphas.set(i, alpha); mRadius.set(i, radius + 1); }else if(alpha < 0 && mImageRadius+radius > mMaxRadius){ // 當最外面那個圓達到了View的寬度時,移除,保證內存的回收 mRadius.remove(i); mAlphas.remove(i); } } // 判斷當波浪圓擴散到指定寬度時添加新擴散圓 // if (mRadius.get(mRadius.size() - 1) == mWidth) { // addWave(); // } if (mIsWave) { invalidate(); } }
思路:一直不停的在根據list中的半徑值和alpha值在畫對應的圓,list中有多少個圓,就會畫出多少個,當alpha的值小於0了,視覺上,人眼看不到了,或者已經到了View的邊界,就將他移除。減小內存的佔用。markdown
4.提供的一些公共的方法,方便調用app
/** * 開始擴散 */ public void start() { mIsWave = true; invalidate(); } /** * 中止擴散 */ public void stop() { mIsWave = false; } /** * 是否擴散中 */ public boolean isWave() { return mIsWave; } /** * 設置波浪圓顏色 */ public void setColor(int colorId) { mColor = colorId; } /** * 設置波浪圓之間間距 */ public void setWidth(int width) { mWidth = width; } /** * 設置中心圓半徑 */ public void setMaxRadius(int maxRadius) { mMaxRadius = maxRadius; } public void setImageRadius(int imageRadius) { mImageRadius = imageRadius; } public void addWave(){ mAlphas.add(255); mRadius.add(0); }
5.Activity中的調用和xml佈局ide
WaveActivity.java佈局
private ImageView head; private WaveView wave; private ScaleAnimation scaleAnimation; private MediaPlayer mPlayer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_wave); scaleAnimation = new ScaleAnimation(1.2f, 1f, 1.2f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); scaleAnimation.setDuration(500); scaleAnimation.setFillAfter(true); wave = (WaveView) findViewById(R.id.wave); head = (ImageView) findViewById(R.id.head); mPlayer = MediaPlayer.create(this, R.raw.water_wave); head.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { wave.addWave(); head.startAnimation(scaleAnimation); if(mPlayer.isPlaying()){ mPlayer.stop(); try { mPlayer.prepare(); } catch (IOException e) { e.printStackTrace(); } } mPlayer.start(); } }); wave.start(); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); wave.setImageRadius(head.getWidth()/2); }
activity_wave.xmlpost
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/black" > <com.dx.demi.view.WaveView android:id="@+id/wave" android:layout_width="match_parent" android:layout_height="match_parent" app:wave_color="@color/yellow" app:wave_coreImageRadius="30" app:wave_width="40"/> <ImageView android:id="@+id/head" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/user" android:layout_centerInParent="true"/> </RelativeLayout>
6.須要注意的細節
/** * 獲取View的寬高在構造方法中拿不到的,getWidth(),getHeight()都會爲零 * @param hasWindowFocus */ @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); mMaxRadius = getWidth() > getHeight() ? getHeight() / 2 : getWidth() / 2; invalidate(); } /** * 防止window是去焦點時,也就是應用在後臺時,中止View的繪製 */ @Override public void invalidate() { if (hasWindowFocus()) { super.invalidate(); } }
1.我目前貼的代碼實現的是效果3(咻一咻):點擊圖片,圖片會放大,同時會播放背景音樂(網上隨便找了個還聽得過去的),並增長一個新的波浪圓。
2.效果1:打開View的界面,每一個一段固定的距離,就會產生一個新的波浪圓。波浪圓是空心的。這個只要設置畫筆的風格爲STROKE,並設置StrokeWidth。Activity中註釋掉動畫,註釋掉點擊事件,註釋掉音樂播放。可是要記得一開始就得添加新圓,否則啥都沒有。畢竟不像效果3那樣,點擊圖片纔有。
mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(5); mAlphas.add(255); mRadius.add(0);
3.效果2:打開View的界面,每一個一段固定的距離,就會產生一個新的波浪圓。波浪圓是實心的。Activity中註釋掉動畫,註釋掉點擊事件,註釋掉音樂播放。設置畫筆的風格爲FILL就OK了,默認風格就是FILL。
在完成這個自定義View的時候,花了很長時間。我也不是一開始就是這樣的一個思路。沒有想到過用集合來存放半徑,沒有第一時間想到getWidth()的值在構造方法中會獲取不到.因此仍是得多想,多嘗試。咱們纔會進步,提升!在自定義View時,必定要明白一個真理:」onDraw()方法從新調用時,會抹去上一次繪製過的圖像「。有些地方,我寫的可能不是很好,還須要優化。歡迎點評!