android自定義布局實現優惠券效果

最近需要實現一個凹凸效果的擬物化優惠券效果,我一看,本來想用.9圖片做背景實現的,雖說圖片做背景實現省事兒方便,但是能用代碼實現最好不過了,最終我還是選擇了用代碼來實現,于是有了下文。

最終效果圖

demo下載地址

###1.完整代碼 先看完整的代碼,后面我們再對代碼逐一的解釋

public class CouponDisplayView extends RelativeLayout {private Paint mPaint;private Paint mPaint2;
// 圓間距private float gap = 0;
// 半徑private float radius = 20;
// 圓數量private int circleNum;private float remain;private int color;public CouponDisplayView(Context context) {super(context);}public CouponDisplayView(Context context, AttributeSet attrs) {super(context, attrs);mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setDither(true);mPaint.setColor(color);mPaint.setStyle(Paint.Style.FILL);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);if (remain == 0) {remain = (int) (w - gap) % (2 * radius + gap);}circleNum = (int) ((w - gap) / (2 * radius + gap));}public CouponDisplayView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);for (int i = 0; i < circleNum; i++) {float x = gap + radius + remain / 2 + ((gap + radius * 2) * i);canvas.drawCircle(x, 0, radius, mPaint);}mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint2.setDither(true);mPaint2.setColor(getResources().getColor(R.color.divider_color_car));mPaint2.setStyle(Paint.Style.FILL);Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE);paint.setColor(Color.DKGRAY);Path path = new Path();path.moveTo(0, getHeight() / 2 + 60);path.lineTo(getWidth(), getHeight() / 2 + 60);PathEffect effects = new DashPathEffect(new float[]{15, 15, 15, 15}, 2);paint.setPathEffect(effects);canvas.drawPath(path, paint);canvas.drawCircle(0, getHeight() / 2 + 60, radius, mPaint2);canvas.drawCircle(getWidth(), getHeight() / 2 + 60, radius, mPaint2);}public void setColor(int color) {this.color = color;}
}
復制代碼

###2.方法解釋 1、CouponDisplayView繼承自RelativeLayout,通過打印日志測試已知View的執行順序如下:

CouponDisplayView(context,attrs,defStyleAttr)
CouponDisplayView(context,attrs)
onSizeChanged()
onDraw()
復制代碼

onSizeChanged(int w, int h, int oldw, int oldh) 當view的大小發生變化時觸發 onDraw(Canvas canvas) 負責將View繪制在屏幕上 public CouponDisplayView(Context context) Java代碼直接new一個CouponDisplayView實例的時候,會調用這個只有一個參數的構造函數 public CouponDisplayView(Context context, AttributeSet attrs) 在默認的XML布局文件中創建的時候調用這個有兩個參數的構造函數。AttributeSet類型的參數負責把XML布局文件中所自定義的屬性通過AttributeSet帶入到View內; public CouponDisplayView(Context context,AttributeSet attrs, int defStyleAttr) 構造函數中第三個參數是默認的Style,這里的默認的Style是指它在當前Application或者Activity所用的Theme中的默認Style,且只有在明確調用的時候才會調用

###3.代碼實現思路 從上面的效果圖來看,這個自定義View和普通的Linearlayout,RelativeLayout一樣,只是上下兩邊多了類似于半圓鋸齒的形狀,我們需要在上下兩條線上畫一個個白色的小圓來實現這種效果。 假如我們上下線的半圓以及半圓與半圓之間的間距是固定的,那么不同尺寸的屏幕肯定會畫出不同數量的半圓,那么我們只需要根據控件的寬度來獲取能畫的半圓數。 我們觀察效果圖會發現,圓的數量總是圓間距數量-1,

也就是說,假設圓的數量是circleNum,那么圓間距就是circleNum+1,所以我們可以根據這個計算出circleNum: 這里gap就是圓間距,radius是圓半徑,w是view的寬

circleNum = (int) ((w-gap)/(2*radius+gap));
復制代碼

1 、重寫onSizeChanged()方法,根據上面的圓的半徑和圓間距來計算需要畫的圓數量circleNum

    @Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);if (remain == 0) {remain = (int) (w - gap) % (2 * radius + gap);}circleNum = (int) ((w - gap) / (2 * radius + gap));}
復制代碼

2.接下來只需要重寫onDraw()方法,簡單的根據circleNum的數量將一個一個的圓繪制在屏幕上

    @Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);for (int i = 0; i < circleNum; i++) {float x = gap + radius + remain / 2 + ((gap + radius * 2) * i);canvas.drawCircle(x, 0, radius, mPaint);}
}
復制代碼

3.畫中間的黑色虛線

  Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE);paint.setColor(Color.DKGRAY);Path path = new Path();path.moveTo(0, getHeight() / 2 + 60);path.lineTo(getWidth(), getHeight() / 2 + 60);PathEffect effects = new DashPathEffect(new float[]{15, 15, 15, 15}, 2);paint.setPathEffect(effects);canvas.drawPath(path, paint);
復制代碼

4.畫兩邊居中的半圓

    mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint2.setDither(true);mPaint2.setColor(getResources().getColor(R.color.divider_color_car));mPaint2.setStyle(Paint.Style.FILL);canvas.drawCircle(0, getHeight() / 2 + 60, radius, mPaint2);canvas.drawCircle(getWidth(), getHeight() / 2 + 60, radius, mPaint2);
復制代碼

代碼分析完畢

###3.設置自定義樣式屬性

考慮到復用地方不是很多,所以上面的代碼沒有寫自定義樣式屬性,而是用了public void setColor(int color) {this.color = color;}有需要設置自定義屬性的我在這里寫一下哈,嘻嘻

1、在res/values/ 下建立一個attr.xml , 在里面定義我們的需要用到的屬性以及聲明相對應屬性的取值類型

<?xml version="1.0" encoding="utf-8"?>
<resources>//半圓顏色<attr name="radiusColor" format="color" /><declare-styleable name="CouponDisplayView"><attr name="radiusColor" /></declare-styleable></resources>
復制代碼

上面定義的半圓顏色的屬性,format屬性的取值類型總共有10種,包括:stringcolordemensionintegerenumreferencefloatbooleanfractionflag

2、然后在XML布局中聲明我們的自定義View

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:custom="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent">
<--注意:一定要引入xmlns:custom="http://schemas.android.com/apk/res-auto"
custom名字可以自定義--><com.xxx.xxx.CouponDisplayViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:background="#FBB039"android:orientation="horizontal"android:padding="16dp"custom:radiusColor="@Color/red">
............</com.xxx.xxx.CouponDisplayView>
</LinearLayout>
復制代碼

3、在View的構造方法中,獲得我們的xml布局文件中定義的顏色

public CouponDisplayView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);Log.d("mDebug", "CouponDisplayView context,attrs,defStyleAttr");
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CouponDisplayView, defStyleAttr, 0);for (int i = 0; i < a.getIndexCount(); i++) {int attr = a.getIndex(i);switch (attr) {case R.styleable.CouponDisplayView_radiusColor:radius = a.getDimensionPixelSize(R.styleable.CouponDisplayView_radiusColor, 10);break;}}a.recycle();
}
復制代碼

OK,設置自定義樣式屬性到此就寫完了。

轉載于:https://juejin.im/post/5bdda7e451882516bb02e11b

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/253143.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/253143.shtml
英文地址,請注明出處:http://en.pswp.cn/news/253143.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

郵件實現詳解(四)------JavaMail 發送(帶圖片和附件)和接收郵件

好了&#xff0c;進入這個系列教程最主要的步驟了&#xff0c;前面郵件的理論知識我們都了解了&#xff0c;那么這篇博客我們將用代碼完成郵件的發送。這在實際項目中應用的非常廣泛&#xff0c;比如注冊需要發送郵件進行賬號激活&#xff0c;再比如OA項目中利用郵件進行任務提…

運放搭建電壓電流轉換電路分析

如下圖電路&#xff0c;電流可以轉換成電壓&#xff0c;電壓也可以轉換成電流&#xff1b; 根據虛斷&#xff1a;(Vi–V1)/R2 (V1–V4)/R6 &#xff08;a&#xff09; 同理 (V3–V2)/R5V2/R4 &#xff08;b&#xff09; 根據虛短&#xff1a; V1V2 &#xff08;c&#xff09…

centos7裝完chrome無法使用yum問題解決

2019獨角獸企業重金招聘Python工程師標準>>> 續前文裝好chrome后&#xff0c;yum居然用不了&#xff0c;提示錯誤“Basic XLib functionality test failed!” 呵呵。。。呵呵了.... 【題外話~個人真心覺得pythonseleniumchrome在linux環境下開發和使用 簡直蛋疼無比…

實驗二第二部分

第二部分 FTP協議分析 1. 兩個同學一組&#xff0c;A和B。 2.A同學架設FTP服務器&#xff0c;并設置用戶名和密碼&#xff0c;例如gao / gao 3.B同學在機器中安裝Wireshark&#xff0c;并將其打開&#xff1b;之后用用戶名和密碼登陸A同學的FTP服務器&#xff0c;并上傳一張圖片…

運放搭建的跟隨電路作用與分析

電壓跟隨器&#xff0c;顧名思義就是輸出電壓與輸入電壓是相同的&#xff0c;就是說電壓跟隨器的電壓放大倍數恒小于且接近1。 電壓跟隨器的顯著特點就是&#xff0c;輸入阻抗高&#xff0c;而輸出阻抗低。 根據其顯著特點&#xff0c;常見的作用如下&#xff1a; 1- 緩沖 在…

Spring Boot(十二)單元測試JUnit

一、介紹 JUnit是一款優秀的開源Java單元測試框架&#xff0c;也是目前使用率最高最流行的測試框架&#xff0c;開發工具Eclipse和IDEA對JUnit都有很好的支持&#xff0c;JUnit主要用于白盒測試和回歸測試。 白盒測試&#xff1a;把測試對象看作一個打開的盒子&#xff0c;程序…

介紹TCP/udp比較好的博客

http://blog.csdn.net/nana_93/article/details/8743525

Kubernetes容器上下文環境

目錄貼&#xff1a;Kubernetes學習系列 下面我們將主要介紹運行在Kubernetes集群中的容器所能夠感知到的上下文環境&#xff0c;以及容器是如何獲知這些信息的。 首先&#xff0c;Kubernetes提供了一個能夠讓容器感知到集群中正在發生的事情的方法&#xff1a;環境變量。作為容…

Shell-腳本只能運行1次

用空文件進行判斷 pathpwd if [ -f ${path}/.runned ]; then {echo "This script can only execute once! You have runned it!"exit } elsetouch ${path}/.runned fi 轉載于:https://www.cnblogs.com/music378/p/7677648.html

運放電壓跟隨電路應用

電壓跟隨器的顯著特點&#xff1a;輸入阻抗高&#xff0c;輸出阻抗低。 如下所示為利用放大器搭建的電壓跟隨電路&#xff0c;方便測量電壓大小&#xff1a; 此電路目的是測量電池電壓&#xff0c;電池電壓范圍&#xff08;3~4.2V&#xff09;分壓后最大電壓為2.1V 屬于3.3V電…

Mac與Phy組成原理的簡單分析

Mac與Phy組成原理的簡單分析 2011-12-28 15:30:43 //http://blog.chinaunix.net/uid-20528014-id-3050217.html 本文乃fireaxe原創&#xff0c;使用GPL發布&#xff0c;可以自由拷貝&#xff0c;轉載。但轉載請保持文檔的完整性&#xff0c;并注明原作者及原鏈接。內容可任意使…

[BZOJ3994][SDOI2015]約數個數和

3994: [SDOI2015]約數個數和 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 1104 Solved: 762 [Submit][Status][Discuss]Description 設d(x)為x的約數個數&#xff0c;給定N、M&#xff0c;求 Input 輸入文件包含多組測試數據。 第一行&#xff0c;一個整數T&#xff0…

月蝕動漫獲快看漫畫600萬元A輪戰略投資,走國漫精品化路線

11月5日消息&#xff0c;月蝕動漫宣布獲得快看漫畫600萬元A輪戰略投資。 據了解&#xff0c;月蝕動漫曾于2017年1月獲得原力創投的百萬級種子輪投資&#xff0c;2018年1月獲得英諾天使基金的百萬級天使輪投資。 據月蝕動漫創始人賀小桐透露&#xff0c;團隊能在行業寒冬期獲得…

大力智能臺燈T6 結構拆解

近幾年教育硬件產品層出不窮&#xff0c;教育硬件賽道布局時間較長的有網易、訊飛、步步高系等公司&#xff0c;2020年10月&#xff0c;字節跳動旗下大力教育經過兩年多的調研和研發&#xff0c;高調推出首款智能硬件產品“大力智能作業臺燈” T5。 上市一年取得不錯的銷售成績…

C++靜態庫與動態庫

http://www.cnblogs.com/skynet/p/3372855.html

第5章 IDA Pro

5.1 加載一個可執行文件 默認情況下IDA Pro的反匯編代碼中不包含PE頭或資源節&#xff0c;可以手動指定加載。 5.2 IDA Pro接口 5.2.1 反匯編窗口模式 二進制模式/圖形模式&#xff1a; 圖形模式&#xff1a;紅色表示一個條件跳轉沒有被采用&#xff0c;綠色表示這個條件跳轉被…

樹鏈剖分(模板)

luogu題庫 題目描述 如題&#xff0c;已知一棵包含N個結點的樹&#xff08;連通且無環&#xff09;&#xff0c;每個節點上包含一個數值&#xff0c;需要支持以下操作&#xff1a; 操作1&#xff1a; 格式&#xff1a; 1 x y z 表示將樹從x到y結點最短路徑上所有節點的值都加上…

定制或外購適配器規格需求列表

輸入特性例如輸入電壓180~264VAC 200~264VAC輸入頻率47~63Hz輸入電流0.7A Max功率因素&#xff1e;0.47 10W220VAC浪涌電流&#xff1c;60A電源效率&#xff1e;81.26%空載功耗0.2W 輸出特性例如輸出電壓11.4~12.6V DC輸出電流1.75A紋波要求&#xff1c;120mV 負載調整率5%線性…

使用 typescript ,提升 vue 項目的開發體驗(1)

此文已由作者張漢銳授權網易云社區發布。歡迎訪問網易云社區&#xff0c;了解更多網易技術產品運營經驗。前言&#xff1a;對于我們而言&#xff0c;typescript 更像一個工具官方指南從 vue2.5 之后&#xff0c;vue 對 ts 有更好的支持。根據官方文檔&#xff0c;vue 結合 type…

Linux進程間通信——使用共享內存

//本文轉載http://blog.csdn.net/ljianhui/article/details/10253345下面將講解進程間通信的另一種方式&#xff0c;使用共享內存。一、什么是共享內存顧名思義&#xff0c;共享內存就是允許兩個不相關的進程訪問同一個邏輯內存。共享內存是在兩個正在運行的進程之間共享和傳遞…