HarmonyOS自定義UI之水波紋效果
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
概述
當(dāng)點(diǎn)擊一個(gè)view時(shí),然后一個(gè)水波紋就會(huì)從點(diǎn)擊處擴(kuò)散開(kāi)來(lái),模擬水波背景動(dòng)效實(shí)現(xiàn)。
實(shí)現(xiàn)思路
任何東西都可以在生活中找到案例,我們要做水波紋效果,就想象一下,每個(gè)人應(yīng)該都有把石頭扔進(jìn)進(jìn)水里的經(jīng)歷,首先水波是從中心點(diǎn)的小圓慢慢放大為大圓,然后慢慢消失,我們模擬的時(shí)候只需要畫圓,通過(guò)Canvas. drawCircle(float x, float y, float radius, Paint paint); 方法來(lái)實(shí)現(xiàn),通過(guò)一點(diǎn)點(diǎn)放大半徑在根據(jù)變化速率設(shè)置透明度的方式實(shí)現(xiàn)。
效果如下:

實(shí)現(xiàn)過(guò)程:
通過(guò)計(jì)算view的最大寬度 / 2為布局的最大半徑,最小半徑就是0然后給它一個(gè)插值動(dòng)畫讓它動(dòng)起來(lái),每次點(diǎn)擊就讓它繪制圓,圓的半徑為 (this.radiusMax * 插值動(dòng)畫比例 ),插值動(dòng)畫比例的變化曲率為 0 - 1 根據(jù)比例計(jì)算出半徑從小到大的大小,代碼如下:
- //初始化畫筆
- private void inint() {
- this.animationRunning = false;
- this.paint = new Paint();
- this.paint.setAntiAlias(true);
- this.paint.setStyle(FILLANDSTROKE_STYLE);
- this.paint.setColor(new Color(Color.getIntColor("#0000FF")));//設(shè)置水波紋的顏色
- }
- @Override
- public void onDraw(Component component, Canvas canvas) {
- float touchX = (float) this.getWidth() / 2;
- float touchY = (float) this.getHeight() / 2;
- this.paint.setAlpha(1 - 1* this.ripplePose);//透明都也是從0到1 因?yàn)閞ipplePose 是從0-1變換
- this.radiusMax = component.getWidth()/2;
- float radiusMax2 = component.getWidth()/4;
- //根據(jù)比例設(shè)置半徑大小
- canvas.drawCircle(touchX, touchY, this.radiusMax * this.ripplePose +radiusMax2, this.paint);
- }
this.ripplePose的變化曲率為 0 - 1 根據(jù)比例計(jì)算出半徑從小到大的大小,來(lái)繪制圓,這里我為什么加 radiusMax2是因?yàn)榻o他一個(gè)初始半徑,讓他不要從圓心開(kāi)始,這樣看起來(lái)就比較舒服了, 在點(diǎn)擊的時(shí)候觸發(fā)動(dòng)畫,代碼如下:
- @Override
- public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
- if (touchEvent.getPointerCount() == 1 && touchEvent.getAction() == PRIMARY_POINT_DOWN) { // 一個(gè)手指按下
- this.downX = this.getTouchX(touchEvent, 0);
- this.createAnimation(this.getTouchX(touchEvent, 0), this.getTouchY(touchEvent, 0));
- } else if (touchEvent.getPointerCount() == 1 && touchEvent.getAction() == POINT_MOVE) { // 一個(gè)手指移動(dòng)
- } else if (touchEvent.getPointerCount() == 1 && touchEvent.getAction() == PRIMARY_POINT_UP) { //一個(gè)手指抬起
- this.invalidate();
- }
- return false;
- }
效果如下:
但是當(dāng)我把水波紋應(yīng)用到 PageSlider 中帶有ListContainer 的時(shí)候,滑動(dòng)的時(shí)候也會(huì)觸發(fā)水波紋,所以需要解決事件沖突。
事件沖突解決
在添加了長(zhǎng)按陰影效果后,在滑動(dòng)PageSlider 頁(yè)面的時(shí)候listContainer的子item也會(huì)觸發(fā)點(diǎn)擊事件,導(dǎo)致各種事件沖突,解決方法就是 在Touch事件中計(jì)算定義出各種事件,各個(gè)擊破。
1.點(diǎn)擊事件:抬起時(shí)間-按下時(shí)間 沒(méi)有超過(guò)200ms
2.長(zhǎng)按事件:按下超過(guò)200ms
3.長(zhǎng)按滑動(dòng)事件:移動(dòng)監(jiān)聽(tīng)里面計(jì)算 滑動(dòng)距離超過(guò)20,時(shí)間超過(guò)200 沒(méi)有抬起
4.短按滑動(dòng)事件: 時(shí)間少于200ms 距離超過(guò) 200px 沒(méi)有抬起
5.然后處理各種事件
另外發(fā)現(xiàn),手機(jī)點(diǎn)擊的時(shí)候移動(dòng)事件會(huì)觸發(fā),而模擬器不會(huì)觸發(fā),這個(gè)也需要注意!
這樣就完成了整個(gè)繪制過(guò)程,代碼如下:
- /**
- * 觸摸監(jiān)聽(tīng)
- *
- * @param component view
- * @param touchEvent touchEvent
- * @return 是否消費(fèi)
- */
- public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
- if (touchEvent.getPointerCount() == NUM1 && touchEvent.getAction() == NUM1) {
- this.downX = this.getTouchX(touchEvent, 0);
- this.downY = this.getTouchY(touchEvent, 0);
- this.downTime = System.currentTimeMillis();
- this.isDownPose = true;
- this.isSlide = false;
- isYinYing = false;
- } else if (touchEvent.getPointerCount() == NUM1 && touchEvent.getAction() == NUM3) {
- float upx = this.getTouchX(touchEvent, 0);
- long theTime = System.currentTimeMillis();
- int xjuli = (int) Math.abs(upx - downX);
- int timejuli = (int) Math.abs(theTime - this.downTime);
- if (isDownPose && timejuli > NUM200 && xjuli < NUM2 && !isSlide) {
- this.createAnimation(this.getTouchX(touchEvent, 0), this.getTouchY(touchEvent, 0));
- myevenHandler.sendEvent(1, NUM250);
- this.isSlide = true;
- return true;
- }
- return true;
- } else if (touchEvent.getPointerCount() == NUM1 && touchEvent.getAction() == NUM2) {
- float upx = this.getTouchX(touchEvent, 0);
- long upTimes = System.currentTimeMillis();
- isDownPose = false;
- isYinYing = false;
- int xjuli = (int) Math.abs(upx - downX);
- if (!this.isDownPose && upTimes - this.downTime < NUM200 && xjuli < NUM5) {
- this.isDownPose = false;
- this.createAnimation(this.getTouchX(touchEvent, 0), this.getTouchY(touchEvent, 0));
- } else if (!this.isDownPose && System.currentTimeMillis() - this.downTime > NUM250) {
- this.invalidate();
- } else {
- this.isDownPose = false;
- }
- this.isDownPose = false;
- }
- return true;
- }
- /**
- * 長(zhǎng)按監(jiān)聽(tīng)
- *
- * @param component view
- */
- @Override
- public void onLongClicked(Component component) {
- this.createAnimation(this.downX, this.downY);
- myevenHandler.sendEvent(1, NUM250);
- this.isSlide = true;
- }
- /**
- * 繪制
- *
- * @param var1 Component
- * @param var2 Canvas
- */
- public void onDraw(Component var1, Canvas var2) {
- if (isYinYing) {
- this.paint.setAlpha(NUM03F);
- var2.drawCircle(this.touchX, this.touchY, this.radiusMax * this.ripplePose - 0 / NUM2F, this.paint);
- } else {
- if (this.getWidth() != 0 && this.getHeight() != 0) {
- this.radiusMax = (float) Math.sqrt(this.getWidth()
- * this.getWidth() + this.getHeight() * this.getHeight());
- if (this.rippleType != NUM2) {
- this.radiusMax /= NUM2F;
- }
- this.radiusMax -= (float) this.ripplePadding;
- if (this.isCentered || this.rippleType == 1) {
- this.touchX = (float) this.getWidth() / NUM2F;
- this.touchY = (float) this.getHeight() / NUM2F;
- }
- this.paint.setAlpha(this.rippleAlpha - this.rippleAlpha * this.ripplePose);
- float var3 = 0.0F;
- if (this.rippleType == NUM1 && this.ripplePose > NUM04) {
- this.paint.setStyle(Paint.Style.STROKE_STYLE);
- var3 = this.radiusMax * this.ripplePose - this.radiusMax * (this.ripplePose - NUM04) / NUM06;
- this.paint.setStrokeWidth(this.radiusMax * this.ripplePose
- - this.radiusMax * (this.ripplePose - NUM04) / NUM06);
- } else {
- this.paint.setStyle(Paint.Style.FILL_STYLE);
- }
- var2.drawCircle(this.touchX, this.touchY, this.radiusMax * this.ripplePose - var3 / NUM2F, this.paint);
- }
- }
- }
效果如下:
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)