android自定義形狀
① 關於Android 自定義鍵盤的問題
在activity中使用的時候,首先要屏蔽掉系統軟鍵盤,然後在輸入框獲取焦點的時候彈出你的鍵盤就OK了,鍵盤你可以用button來實現,或者就用一張圖片算坐標重寫ontouch都行;點數字的時候你就把你點的那個數字settext到你的輸入框里,delete的時候你就把你輸入框的文字去掉一位就OK了。如果讓我做的話思路大概是這樣的!
② Android 自定義View之Draw過程(上)
Draw 過程系列文章
Android 展示之三部曲:
前邊我們已經分析了:
這倆最主要的任務是: 確定View/ViewGroup可繪制的矩形區域。
接下來將會分析,如何在這給定的區域內繪制想要的圖形。
通過本篇文章,你將了解到:
Android 提供了關於View最基礎的兩個類:
然而ViewGroup 並沒有約定其內部的子View是如何布局的,是疊加在一起呢?還是橫向擺放、縱向擺放等。同樣的View 也沒有約定其展示的內容是啥樣,是矩形、圓形、三角形、一張圖片、一段文字抑或是不規則的形狀?這些都要我們自己去實現嗎?
不盡然,值得高興的是Android已經考慮到上述需求了,為了開發方便已經預制了一些常用的ViewGroup、View。
如:
繼承自ViewGroup的子類
繼承自View的子類
雖然以上衍生的View/ViewGroup子類已經大大為我們提供了便利,但也僅僅是通用場景下的通用控制項,我們想實現一些較為復雜的效果,比如波浪形狀進度條、會發光的球體等,這些系統控制項就無能為力了,也沒必要去預制千奇百怪的控制項。想要達到此效果,我們需要自定義View/ViewGroup。
通常來說自定義View/ViewGroup有以下幾種:
3 一般不怎麼用,除非布局比較特殊。1、2、4 是我們常用的手段,對於我們常說的"自定義View" 一般指的是 4。
接下來我們來看看 4是怎麼實現的。
在xml里引用MyView
效果如下:
黑色部分為其父布局背景。
紅色矩形+黃色圓形即是MyView繪制的內容。
以上是最簡單的自定義View的實現,我們提取重點歸納如下:
由上述Demo可知,我們只需要在重寫的onDraw(xx)方法里繪制想要的圖形即可。
來看看View 默認的onDraw(xx)方法:
發現是個空實現,因此繼承自View的類必須重寫onDraw(xx)方法才能實現繪制。該方法傳入參數為:Canvas類型。
Canvas翻譯過來一般叫做畫布,在重寫的onDraw(xx)里拿到Canvas對象後,有了畫布我們還需要一支筆,這只筆即為Paint,翻譯過來一般稱作畫筆。兩者結合,就可以愉快的作畫(繪制)了。
你可能發現了,在Demo里調用
並沒有傳入Paint啊,是不是Paint不是必須的?實際上調用該方法後,底層會自動生成Paint對象。
可以看到,底層初始化了Paint,並且給其設置的顏色為在java層設置的顏色。
onDraw(xx)比較簡單,開局一個Canvas,效果全靠畫。
試想,這個Canvas怎麼來的呢,換句話說是誰調用了onDraw(xx)。發揮一下聯想功能,在Measure、Layout 過程有提到過兩者套路很像:
那麼Draw過程是否也是如此套路呢?看見了onDraw(xx),那麼draw(xx)還遠嗎?
沒錯,還真有draw(xx)方法:
可以看出,draw(xx)主要分為兩個部分:
不管是A分支還是B分支,都進行了好幾步的繪制。
通常來說,單一一個View的層次分為:
後面繪制的可能會遮擋前邊繪制的。
對於一個ViewGroup來說,層次分為:
來看看A分支標注的4個點:
(1)
onDraw(canvas)
前面分析過,對於單一的View,onDraw(xx)是空實現,需要由我們自定義繪制。
而對於ViewGroup,也並沒有具體實現,如果在自定義ViewGroup里重寫onDraw(xx),它會執行嗎?默認是不會執行的,相關分析請移步:
Android ViewGroup onDraw為什麼沒調用
(2)
dispatchDraw(canvas),來看看在View.java里的實現:
發現是個空實現,再看看ViewGroup.java里的實現:
也即是說,對於單一View,因為沒有子布局,因此沒必要再分發Draw,而對於ViewGroup來說,需要觸發其子布局發起Draw過程(此過程後續分析),可以類比事件分發過程View、ViewGroup的處理。感興趣的請移步:
Android 輸入事件一擼到底之View接盤俠(3)
(3)
OverLay,顧名思義就是"蓋在某個東西上面",此處是在繪制內容之後,繪制前景之前。怎麼用呢?
以上是給一個ViewGroup設置overLay,效果如下:
你可能發現了,這和設置overLay差不多的嘛,實際還是有差別的。在onDrawForeground(xx)里會重新調整Drawable的尺寸,該尺寸與View大小一致,之前給Drawable設置的尺寸會失效。運行效果如下:
可以看出,ViewGroup都被前景蓋住了。
再來看看B分支的重點:邊緣漸變效果
先來看看TextView 邊緣漸變效果:
加上這倆參數。
實際上系統自帶的一些控制項也使用了該效果,如NumberPicker、YearPickerView
以上是NumberPicker 的效果,可以看出是垂直方向漸變的。
對於View.java 里的onDraw(xx)、draw(xx),ViewGroup.java里並沒有重寫。
而對於dispatchDraw(xx),在View.java里是空實現。在ViewGroup.java里發起對子布局的繪制。
來看看標記的2點:
(1)
設置padding的目的是為了讓子布局留出一定的空隙出來,因此當設置了padding後,子布局的canvas需要根據padding進行裁減。判斷標記為:
FLAG_CLIP_TO_PADDING 默認設置為true
FLAG_PADDING_NOT_NULL 只要有padding不為0,該標記就會打上。
也就是說:只要設置了padding 不為0,子布局顯示區域需要裁減。
能不能不讓子布局裁減顯示區域呢?
答案是可以的。
考慮到一種場景:使用RecyclerView的時候,我們需要設置paddingTop = 20px,效果是:RecyclerView Item展示時離頂部有20px,但是滾動的時候永遠滾不到頂部,看起來不是那麼友好。這就是上述的裁減起作用了,需要將此動作禁止。通過設置:
當然也可以在xml里設置:
(2)
drawChild(xx)
從方法名上看是調用子布局進行繪制。
child.draw(x1,x2,x3)里分兩種情況:
這兩者具體作用與區別會在下篇文章分析,不管是硬體加速繪制還是軟體加速繪制,最終都會調用View.draw(xx)方法,該方法上面已經分析過。
注意,draw(x1,x2,x3)與draw(xx)並不一樣,不要搞混了。
用圖表示:
View/ViewGroup Draw過程的聯系:
一般來說,我們通常會自定義View,並且重寫其onDraw(xx)方法,有沒有繪制內容的ViewGroup需求呢?
是有的,舉個例子,大家可以去看看RecyclerView ItemDecoration 的繪制,其中運用到了ViewGroup draw(xx)、ViewGroup onDraw(xx) 、View onDraw(xx)繪制的先後順序來實現分割線,分組頭部懸停等功能的。
本篇文章基於 Android 10.0
③ Android自定義控制項總結
每個view的坐標系原點為左上角那個點,水平方向為x軸,右正左負,豎直方向為y軸,下正上負。
canvas.drawColor //繪制區域塗上顏色(設置底色/蒙層)
canvas.drawCircle(float centerX(圓心X坐標),float centerY(圓心Y坐標),float radius(圓的半徑,單位像素),Paint paint)
canvas.drawBitmap
canvas.drawRect(float left,float top,float right,float bottom,Paint paint) //畫矩形
canvas.drawRect(RecF rect,Paint paint)
canvas.drawRect(Rect rect,Paint paint)
canvas.drawPoint(float x(點X軸坐標),float y(點Y軸坐標),Paint paint)//畫點
點的大小 ->paint.setStrokeWidth(width)
點的形狀 ->paint.setStrokeCap(cap)
ROUND(圓形),BUTT(平頭),SQUARE(方頭)
canvas.drawPoints()//批量畫點
canvas.drawOval(float left(左邊界點),float top(上邊界點),float right(右邊界點),float bottom(下邊界點),Paint paint) //畫橢圓
canvas.drawLine(float startX(起點X軸坐標),float startY(起點Y軸坐標),float stopX(終點X軸坐標),float stopY(終點X軸坐標),Paint paint) (setStyle對直線沒有影響)
canvas.drawLines(批量畫線)
canvas.drawRoundRect(float left,float top,float right,float bottom,float rx(圓角的橫向半徑),float ry(圓角的縱向坐標),Paint paint)//畫圓角矩形
canvas.drawRoundRect(RectF rect,float rx, float ry,Paint paint)
canvas.drawArc(float left, float top, float right, float bottom, float startAngle(起始角度,順時針為正,逆時針為負), float sweepAngle(弧形劃過角度), boolean useCenter(是否連接到圓心), Paint paint) //繪制弧形或扇形 根據弧形所在橢圓進行繪制
canvas.drawPath() //通過描述路徑的方式來繪制圖形
path.addXxx() —添加子圖形
path.addCircle(x,y,radius,dir(路徑方向:順時針/逆時針))
path.xxxTo —畫線
path.lineTo()
path.rLineTo()
path.close() —封閉當前圖形
path.setFillType(Path.FillType ft) //設置填充模式
canvas.drawBitmap(Bitmap bitmap,float left,float top,Paint paint);//畫bitmap
canvas.drawBitmap(Bitmap bitmap,Rect src,RectF dst,Paint paint)
canvas.drawBitmap(Bitmap bitmap,Rect src,Rect dst,Paint paint)
canvas.drawBitmap(Bitmap bitmap,Matrix matrix,Paint paint)
canvas.drawText(String text,float x(起點x坐標),float y(起點y坐標),Paint paint) //繪制文字
Paint.setStyle //設置繪制模式
FILL 填充模式(默認)
STROKE 畫線模式
FILL_AND_STROKE 既畫線又填充
Paint.setStrokeWidth //設置線條寬度 (僅在style:Stroke、FILL_AND_STROLE下有效)
Paint.setTextSize //設置文字大小
Paint.setAntiAlias //設置抗鋸齒開關
Paint.setTextSize(float textSize)//設置文字大小
Paint.setStrokeJoin(Paint.Join join) //設置拐角的形狀
MITER//尖角(默認)
BEVEL//平角
ROUND//圓角
Paint.setStokeMiter(float miter)//設置MITER型拐角的延長線的最大值
設置顏色
直接設置顏色
Paint.setColor(int color)
Paint.setARGB(int a,int r,int g,int b)
Paint.setShader(Shader shader) //設置shader
LinearGradient 線性漸變
RadialGradient 輻射漸變
SweepGradient 掃描漸變
BitmapShader 用bitmap的像素來作為圖形或文字的填充
ComposeShader 混合著色器,多個shader混合使用
Paint.setColorFilter(ColorFilter colorFilter) //設置顏色過濾
Paint.setXfermode(Xfermode xfermode) //以要繪制的內容為源圖像,以View中已有內容作為目標圖像,選取一個PorterDuff.Mode作為繪制內容的顏色處理方案。
色彩優化
Paint.setDither(boolean dither) //設置抖動來優化色彩深度降低時的繪制效果
Paint.setFilterBitmap(boolean filter) //設置雙線性過濾優化Bitmap放大繪制的效果
可以理解為 由馬賽克變成模糊狀態
Paint.setPathEffect(PathEffect effect)//使用PathEffect設置形狀的輪廓效果
CornerPathEffect//把所有的拐角變成圓角
DiscretePathEffect//把線條進行隨機的偏離
DashPathEffect//使用虛線
PathDashPathEffect//使用一個Path來繪制虛線
SumPathEffect//組合效果
ComposePathEffect//組合效果,組合有先後順序
Paint.setShadowLayer(float radius,float dx,float dy,int shadowColor)//添加陰影
Paint.setMaskFilter(MaskFilter maskfilter)//在繪制層上方的附加效果
BlurMaskFilter //模糊效果
new BlurMaskFilter(float radius(模糊范圍),BlurMaskFilter.Blur style(模糊類型))
EmbossMaskFilter//浮雕效果
new EmbossMaskFilter(float[] direction(光源的方向),float ambient(環境光強度),float specular(炫光系數),float blurRadius(光線范圍))
獲取繪制的Path
getFillPath(Path src,Path dst)//實際path
getTextPath(Stirng text,int start,int end,float x,float y,Path)/getTextPath(char[] text,int index,int count,float x,float y,Path path)//文字的path
drawTextOnPath()//沿一條Path來繪制文字
StaticLayout //繪制文字,支持換行
paint.setFakeBoldText(booleab fakeBoldText)//是否使用偽粗體
paint.setStrikeThruText()//是否加刪除線
paint.setUnderLineText(boolean underlineText)//是否加下劃線
paint.setTextSkewX(float skewX)//設置文字橫向錯切角度
paint.setTextScaleX(float scaleX)//設置文字橫向放縮
paint.setLetterSpacing(float letterSpacing)//設置字元間距,默認為0
paint.setTextAlign(Paint.Align align)//LEFT、CENTER、RIGHT默認為LEFT
paint.setTextLocale(Locale locale)/paint.setTextLocales(LocaleList locales) //設置繪制所用的地域
paint.setHinting(int mode)//是否啟用字體微調
測量文字尺寸類:
paint.getFontSpacing();//獲取推薦的行距
paint.getFontMetrics();//獲取point的FontMetrics
baseline:基準線
ascent/descent:普通字元的頂部和底部范圍
top/bottom:限制字型的頂部和底部
leading:行的額外間距,即上一行字的bottm與下一行字的top距離
paint.getTextBounds(String text(測量的文字),int start(文字的起始位置),int end(文字的結束位置),Rect bounds(文字顯示範圍的對象))//獲取文字的顯示範圍
paint.measureText(String text)//測量文字佔用的寬度
measureText()>getTextBounds()
paint.getTextWidths(String text,float[] widths)//獲取字元串中每個字元的寬度,並把結果填入參數widths
paint.breakText(String text((要測量的文字),boolean measureForwards(測量的方向),float maxWidth(寬度上限(超出上限會截斷文字)),float[] measuredWidth(用於接受數據))//測量完成後會把文字寬度賦給measureWidth[0]
paint.getRunAdvance(CharSequence text,int start(文字的起始坐標),int end(文字的結束坐標),int contextStart(上下文的起始坐標),int ContextEnd(上下文的結束坐標),boolean isRtl(文字的方向),int offset(字數的偏移))//計算某個字元處游標的x坐標
paint.getOffsetForAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance)//計算出文字中最接近這個位置的字元偏移量
paint.hasGlyph(String s)//檢查指定的字元串是否是一個單獨的字型
canvas.clipRect()//范圍裁剪
canvas.clipPath()//根據范圍裁剪
canvas.translate(float dx,float dy)//位移
canvas.rotate(float degrees,float px,float py)//旋轉
canvas.scale(float sx(橫向縮放倍數),float sy(縱向縮放倍數),float px,float py)//縮放
canvas.skew(float sx(x軸的錯切系數),float sy(y軸的錯切系數))//錯切
canvas.setMatrix(matrix)//用Matrix直接替換Canvas當前的變換矩陣
canvas.concat(matrix)//用Canvas當前的變換矩陣和Matrix相乘
Camera.rotate*()//三維旋轉
1、super.draw()//總調度方法
2、super.onDraw()
3、dispatchDraw()//繪制子View的方法
繪制順序:
draw()總調度方法,view的繪制過程都發生在draw()方法里
1、背景(drawBackground()不能重寫)-------android:background:/View.setBackgroundXxx()
2、主體(onDraw())
3、子View(dispatchDraw())
4、滑動邊緣漸變和滑動條(onDrawForeground())-------android:scrollbarXxx/View.setXXXScrollBarXXX()
5、前景(onDrawForeground())-------android:foreground/View.setForeground()
view.animate().translationX()//x軸偏移
1、如果是自定義控制項,需要添加setter、getter方法
2、ObjectAnimator.ofXXX()創建ObjectAnimator對象
3、用start()方法執行動畫
setDuration(int ration)//設置動畫時長
setInterpolator(Interpolator interpolator)//設置插值器
ViewPropertyAnimator.setListener()/ObjectAnimator.addListener()
ViewPropertyAnimator.setUpdateListener()/ObjectAnimator.addUpdateListener()
ObjectAnimator.addPauseListener()
ViewPropertyAnimator.withStartAction/EndAction()
ArgbEvaluator//顏色漸變動畫
PropertyValuesHolder//同一個動畫中改變多個屬性
PropertyValuesHolders.ofKeyframe()//把同一個屬性拆分
AnimatorSet//多個動畫配合執行
targetSdkVersion>=14,硬體加速默認開啟
view.setLayerType()
LAYER_TYPE_SOFTWARE:使用軟體來繪制View Layer,繪制到Bitmap,並順便關閉硬體加速
LAYER_TYPE_HARDWARE:使用GPU來繪制View Layer,繪制到OpenGL texture(如果硬體加速關閉,那麼行為和LAYER_TYPE_SOFTWARE一致)
LAYER_TYPE_NONE:關閉View Layer
View Layer可以加速無invalidate()(例如動畫)時的刷新效率,但對於需要調用invalidate()的刷新無法加速
硬體加速並不支持所有的繪制操作
1、測量(measure)
View:View在onMeasuer中會計算自己的尺寸然後保存
ViewGroup:ViewGroup在onMeasure中會調用所有子View的measure讓它們進行自我測量,並根據子View
計算出的期望尺寸來計算他們的事跡尺寸和位置然後保存。
2、布局(layout)
View:無子View所以onLayout不做任何處理
ViewGroup:ViewGroup在onLayout中會調用自己所有子View的layout方法,把他們的尺寸、位置傳給他們, 讓他們完成自我布局。
MeasureSpec = mode + size :父類傳遞過來給當前View的一個建議值
MeasureSpec.getMode(int spec)//獲取模式
MeasureSpec.getSize(int spec)//獲取數值
限制分類:
UNSPECIFIED(不限制)
AT_MOST(限制上限)->wrap_content
EXACTLY(限制固定值)->match_parent/具體值
1、重寫onMeasure來修改已有的View尺寸
(1)、重寫onMeasure方法,調用super.onMeasure觸發原有的自我測量。
(2)、在super.onMeasure下用getMeasureWidth與getMeasureHeigh獲取之前測量的結果,使用自己的演算法計算新結果。
(3)、調用setMeasureDimension保存新結果。
2、重寫onMeasure來全新定製自定義View的尺寸
與1區別,保證計算的同時,保證結果滿足父View給出的尺寸限制
(1)重寫onMeasure,計算出View的尺寸
(2)使用resolve讓子View的計算結果符合父View的限制,也可不使用該方法自己定義
3、重寫onMeasure和onLayout來全新定製自定義ViewGroup的內部布局
兩個注意點:
子控制項間的margin值
1、重寫generateLayoutParams()和generateDefaultLayoutParams()
2、獲取margin值 MarginLayoutParams lp = (MarginLayoutParams )child.getLayoutParams()
子控制項間的padding值
1、測量後直接getPaddingLeft、getPaddingTop、getPaddingRight、getPaddingBottom
重寫onMeasure來計算內部布局
(1)調用每個子View的measure來計運算元View的尺寸
結合layout_xxx和自己可用空間
(2)計運算元View的位置並保存子View的尺寸和位置
(3)計算自己的尺寸並用setMeasureDimension保存
重寫onLayout來擺放子View
(1)調用每個子View的layout,讓他們保存自己的位置和尺寸
view工作原理
觸摸事件
1、ACTION_DOWN:手指剛接觸屏幕,按下去的那一瞬間
2、ACTION_MOVE:手指在屏幕上移動
3、ACTION_UP:手指從屏幕上松開的瞬間
事件序列:從ACTION_DOWN -> ACTION_UP
ViewGroup:
DispatchTouchEvent
• return true:表示該View內部消化掉了所有事件
• return false:表示事件在本層不再繼續進行分發,並交由上層控制項的onTouchEvent方法進行消費
• return super.dispatchTouchEvent(ev):默認事件將分發給本層的事件攔截onInterceptTouchEvent方法 進行處理
OnInterceptTouchEvent
• return true:表示將事件進行攔截,並將攔截到的事件交由本層控制項的onTouchEvent進行處理
• return false:表示不對事件進行攔截,事件得以成功分發到子View
• return super.onInterceptTouchEvent(ev):默認表示不攔截該事件,並將事件傳遞給下一層View的 dispatchTouchEvent
OnTouchEvent 默認false
• return true:表示onTouchEvent處理完事件後消費了此次事件
• return fasle:表示不響應事件,那麼該事件將會不斷向上層View的onTouchEvent方法傳遞,直到某個View的 onTouchEvent方法返回true
• return super.dispatchTouchEvent(ev):表示不響應事件,結果與return false一樣
子View不存在分發:
• DispatchTouchEvent 事件分發
• OnTouchEvent 默認true
如下圖為事件分發流程圖:
---------------------- 以上總結部分源自Hencoder教程 ------------------------------
④ 如何自定義Android Dialog的樣式
如何自定義Android Dialog的樣式? Android 中自定義Dialog的樣式,主要是通過自定義的xml,然後載入到dialog的背景中,如下步驟:
1、自定義Dialog
final Dialog dialog = new Dialog(this, R.style.Theme_dialog);
2、窗口布局
View contentView = LayoutInflater.from(this).inflate(R.layout.select_list_dialog,null);
3、把設定好的窗口布局放到dialog中
dialog.setContentView(contentView);
4、設定點選視窗空白處取消會話
dialog.setCanceledOnTouchOutside(true);
5、具體的操作
ListView msgView = (ListView)contentView.findViewById(R.id.listview_flow_list);
6、展示視窗
dialog.show();例:final Dialog dialog = new Dialog(this,R.style.Theme_dialog);View contentView =LayoutInflater.from(this).inflate(R.layout.select_list_dialog, null);dialog.setContentView(contentView);dialog.setCanceledOnTouchOutside(true);ListView msgView = (ListView)contentView.findViewById(R.id.listview_flow_list);TextView titleText = (TextView)contentView.findViewById(R.id.title);titleText.setText("請選擇銀行卡");SelectBankCardDialogAdapter adapter =new SelectBankCardDialogAdapter(this, mBankcardList);msgView.setAdapter(adapter);msgView.setOnItemClickListener(newOnItemClickListener() {@Overridepublic void onItemClick(AdapterViewparent, View view, int position, long id) {Toast.makeText(RechargeFlowToMobileActivity.this, position+"",0).show();mSelectCard =mBankcardList.get(position);String area = mSelectCard.getBank_card();mCardNumberText.setText(area);dialog.di *** iss();}});Button closeBtn = (Button)contentView.findViewById(R.id.close);closeBtn.setClickable(true);closeBtn.setOnClickListener(newView.OnClickListener() {@Overridepublic void onClick(View v) {dialog.di *** iss();}});dialog.show();
以上就是在Android開發自定義dialog樣式的方法和步驟,android很多的控制元件都提供了介面或者方法進行樣式的定義和修改。
如何自定義android Button樣式
返回部落格列表
轉 android自定義button樣式
sumpower
釋出時間: 2014/02/25 19:56
閱讀: 4162
收藏: 0
點贊: 0
評論: 0
摘要
android自定義button樣式
在Android開發應用中,預設的Button是由系統渲染和管理大小的。而我們看到的成功的移動應用,都是有著酷炫的外觀和使用體驗的。因此,我們在開發產品的時候,需要對預設按鈕進行美化。在本篇里,筆者結合在應用開發中的經驗,探討一下自定義背景的按鈕、自定義形狀按鈕的實現方法。
首先看實現效果截圖:
自定義背景的按鈕目前有2種方式實現,向量和點陣圖。
1. 向量圖形繪制的方式
向量圖形繪制的方式實現簡單,適合對於按鈕形狀和圖案要求不高的場合。步驟如下:
(a) 使用xml定義一個圓角矩形,外圍輪廓線實線、內填充漸變色,xml程式碼如下。
view plain
bg_alibuybutton_default.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="地址">
<item>
<shape android:shape="rectangle">
<solid android:color="#FFEC7600" />
<corners
android:LeftRadius="5dip"
android:RightRadius="5dip"
android:bottomLeftRadius="5dip"
android:bottomRightRadius="5dip" />
</shape>
</item>
<item android:="1px" android:bottom="1px" android:left="1px" android:right="1px">
<shape>
<gradient
android:startColor="#FFEC7600" android:endColor="#FFFED69E"
android:type="linear" android:angle="90"
android:centerX="0.5" android:centerY="0.5" />
<corners
android:LeftRadius="5dip"
android:RightRadius="5dip"
android:bottomLeftRadius="5dip"
android:bottomRightRadius="5dip" />
</shape>
</item>
</layer-list>
同樣定義bg_alibuybutton_pressed.xml和bg_alibuybutton_selected.xml,內容相同,就是漸變顏色不同,用於按鈕按下後的背景變化效果。
(b) 定義按鈕按下後的效果變化描述檔案drawable/bg_alibuybutton.xml,程式碼如下。
view plain
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="地址">
<item android:state_pressed="true"
android:drawable="@drawable/bg_alibuybutton_pressed" />
<item android:state_focused="true"
android:drawable="@drawable/bg_alibuybutton_selected" />
<item android:drawable="@drawable/bg_alibuybutton_default" />
</selector>
(c) 在你需要的介面定義檔案中,如layout/main.xml中定義一個Button控制元件。
view plain
<Button
android:layout_width="120dip"
android:layout_height="40dip"
android:text="向量背景按鈕" android:background="@drawable/bg_alibuybutton" />
這樣,自定義背景的按鈕就可以使用了,在實現onClick方法後就可以響應操作。
android自帶的樣式比較難看,如何能夠自定義按鈕的樣式,使其顯示的跟美工設計的效果一樣,現與大家分享下
在layout中新增2個按鈕,從下圖中可以看出在按鈕中呼叫了style和android:background屬性,這兩個屬性一個是自定義樣式,一個是給按鈕新增背景圖片
展開res目錄,可以看到在values目錄下有styles.xml檔案,該檔案用於自定義樣式,雙擊開啟
標注的是我自定義的樣式,name為BtnStyle,當按鈕呼叫自定義樣式的時候訪問這個name
在button中呼叫自定義樣式的方法,比較簡單
如何往按鈕中新增自定義圖片,使按鈕看起來更漂亮些,因不同手機解析度不同,那必然牽扯到圖片的拉伸,在android系統下有個很好的技術「九宮格「,可以對圖片進行處理,只對區域性進行拉伸,給工具目錄儲存在android\sdk\tools\draw9patch.bat,經過該工具處理的圖片以.9.png結尾,放到drawable資料夾中
在Button中通過android:background屬性載入圖片的方法,至此我們自定義的按鈕樣式也就完成了,當然這只是個引子,在具體的專案工程中實現的效果要比這個demo復雜很多,有好的設計思路歡迎交流。
⑤ android 自定義網狀圖
1.第一步首先要分析繪制出六個角的位置
畫幾何圖形 一般都用path去繪制
先計算出六個角度的大小 網狀圖的半徑
形狀到此就繪制玩了
2.第二部繪制對角線的位置
3.最後一步繪制區域的百分比
到此 繪制 形狀就結束了
簡單的封裝了個demo 支持大於3的邊角網狀圖
⑥ android 如何重寫imageview 讓圖片有圓角效果
android 自定義圓角ImageView以及鋸齒的處理
看到很多人開發過程中要使用圓角圖片時,解決方法有:
1.重新繪制一張圖片
2.通過布局來配置
3.通過重寫View來實現
其中1,2在這里就不講了,重點講講方法三的實現。
實現一:通過截取畫布一個圓形區域與圖片的相交部分進行繪制,缺點:鋸齒明顯,設置Paint,Canvas抗鋸齒無效。
package com.open.circleimageview.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.View;
public class CircleImageViewA extends View {
public CircleImageViewA(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CircleImageViewA(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleImageViewA(Context context) {
super(context);
}
private Bitmap bitmap;
private Rect bitmapRect=new Rect();
private PaintFlagsDrawFilter pdf=new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);
private Paint paint = new Paint();
{
paint.setStyle(Paint.Style.STROKE);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
paint.setAntiAlias(true);// 設置畫筆的鋸齒效果。 true是去除,大家一看效果就明白了
}
private Path mPath=new Path();
public void setImageBitmap(Bitmap bitmap)
{
this.bitmap=bitmap;
}
@Override
protected void onDraw(Canvas canvas) {
if(null==bitmap)
{
return;
}
bitmapRect.set(0, 0, getWidth(), getHeight());
canvas.save();
canvas.setDrawFilter(pdf);
mPath.reset();
canvas.clipPath(mPath); // makes the clip empty
mPath.addCircle(getWidth()/2, getWidth()/2, getHeight()/2, Path.Direction.CCW);
canvas.clipPath(mPath, Region.Op.REPLACE);
canvas.drawBitmap(bitmap, null, bitmapRect, paint);
canvas.restore();
}
}
實現二:通過PorterDuffXfermode 方式(注意要設置硬體加速,否則部分機子無效),優點:鋸齒基本沒有
package com.open.circleimageview.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class CircleImageViewB extends View {
public CircleImageViewB(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CircleImageViewB(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CircleImageViewB(Context context) {
super(context);
init();
}
private Bitmap bitmap;
private Rect bitmapRect=new Rect();
private PaintFlagsDrawFilter pdf=new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);
private Paint paint = new Paint();
{
paint.setStyle(Paint.Style.STROKE);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
paint.setAntiAlias(true);// 設置畫筆的鋸齒效果。 true是去除,大家一看效果就明白了
}
private Bitmap mDstB=null;
private PorterDuffXfermode xfermode=new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY);
private void init()
{
try {
if(android.os.Build.VERSION.SDK_INT>=11)
{
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void setImageBitmap(Bitmap bitmap)
{
this.bitmap=bitmap;
}
private Bitmap makeDst(int w, int h)
{
Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bm);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(Color.parseColor("#ffffffff"));
c.drawOval(new RectF(0, 0, w, h), p);
return bm;
}
@Override
protected void onDraw(Canvas canvas) {
if(null==bitmap)
{
return;
}
if(null==mDstB)
{
mDstB=makeDst(getWidth(), getHeight());
}
bitmapRect.set(0, 0, getWidth(), getHeight());
canvas.save();
canvas.setDrawFilter(pdf);
canvas.drawBitmap(mDstB, 0, 0, paint);
paint.setXfermode(xfermode);
canvas.drawBitmap(bitmap, null, bitmapRect, paint);
paint.setXfermode(null);
canvas.restore();
}
}
⑦ android 中既要設置shape 又要設置selector 怎麼辦
shape和selector的結合使用
shape和selector是Android UI設計中經常用到的,比如我們要自定義一個圓角Button,點擊Button有些效果的變化,就要用到shape和selector。可以這樣說,shape和selector在美化控制項中的作用是至關重要的。
1.Shape
簡介
作用:XML中定義的幾何形狀
位置:res/drawable/文件的名稱.xml
使用的方法:
Java代碼中:R.drawable.文件的名稱
XML中:Android:background="@drawable/文件的名稱"
屬性:
<shape> Android:shape=["rectangle" | "oval" | "line" | "ring"]
其中rectagle矩形,oval橢圓,line水平直線,ring環形
<shape>中子節點的常用屬性:
<gradient> 漸變
Android:startColor 起始顏色
Android:endColor 結束顏色
Android:angle 漸變角度,0從上到下,90表示從左到右,數值為45的整數倍默認為0;
Android:type 漸變的樣式 liner線性漸變 radial環形漸變 sweep
<solid > 填充
Android:color 填充的顏色
<stroke > 描邊
Android:width 描邊的寬度
Android:color 描邊的顏色
Android:dashWidth 表示'-'橫線的寬度
Android:dashGap 表示'-'橫線之間的距離
<corners > 圓角
Android:radius 圓角的半徑 值越大角越圓
Android:topRightRadius 右上圓角半徑
Android:bottomLeftRadius 右下圓角角半徑
Android:topLeftRadius 左上圓角半徑
Android:bottomRightRadius 左下圓角半徑
2.Selector
簡介
位置:res/drawable/文件的名稱.xml
使用的方法:
Java代碼中:R.drawable.文件的名稱
XML中:Android:background="@drawable/文件的名稱"
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:Android="http://schemas.android.com/apk/res/android">
<!-- 默認時的背景圖片-->
<item Android:drawable="@drawable/pic1" />
<!-- 沒有焦點時的背景圖片 -->
<item
Android:state_window_focused="false"
android:drawable="@drawable/pic_blue"
/>
<!-- 非觸摸模式下獲得焦點並單擊時的背景圖片 -->
<item
Android:state_focused="true"
android:state_pressed="true"
android:drawable= "@drawable/pic_red"
/>
<!-- 觸摸模式下單擊時的背景圖片-->
<item
Android:state_focused="false"
Android:state_pressed="true"
Android:drawable="@drawable/pic_pink"
/>
<!--選中時的圖片背景-->
<item
Android:state_selected="true"
android:drawable="@drawable/pic_orange"
/>
<!--獲得焦點時的圖片背景-->
<item
Android:state_focused="true"
Android:drawable="@drawable/pic_green"
/>
</selector>
第一個例子:圓角的Button
第二個例子:shape+selector綜合使用的例子 漂亮的ListView
selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:Android="http://schemas.android.com/apk/res/android">
<item Android:state_selected="true">
<shape>
<gradient Android:angle="270" android:endColor="#99BD4C"
android:startColor="#A5D245" />
<size Android:height="60dp" android:width="320dp" />
<corners android:radius="8dp" />
</shape>
</item>
<item Android:state_pressed="true">
<shape>
<gradient Android:angle="270" android:endColor="#99BD4C"
android:startColor="#A5D245"/>
<size Android:height="60dp" android:width="320dp" />
<corners android:radius="8dp" />
</shape>
</item>
<item>
<shape>
<gradient Android:angle="270" android:endColor="#A8C3B0"
android:startColor="#C6CFCE" />
<size Android:height="60dp" android:width="320dp" />
<corners android:radius="8dp" />
</shape>
</item>
</selector>
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
Android:layout_width="fill_parent"
android:layout_height="wrap_content"
Android:background="@drawable/selector"
>
<ImageView
Android:id="@+id/img"
Android:layout_width="wrap_content"
android:layout_height="wrap_content"
Android:layout_gravity="center_vertical"
android:layout_marginLeft="20dp"
/>
<TextView
Android:text="data"
android:id="@+id/title"
Android:layout_width="fill_parent"
android:layout_height="wrap_content"
Android:gravity="center_vertical"
android:layout_marginLeft="20dp"
Android:layout_marginTop="20dp"
android:textSize="14sp"
Android:textStyle="bold"
android:textColor="@color/black"
>
</TextView>
</LinearLayout>
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
Android:layout_width="fill_parent"
android:layout_height="wrap_content"
Android:background="#253853"
>
<ListView
Android:id="@+id/list"
Android:layout_width="match_parent"
android:layout_height="match_parent"
Android:cacheColorHint="#00000000"
android:divider="#2A4562"
Android:dividerHeight="3px"
android:listSelector="#264365"
Android:drawSelectorOnTop="false"
>
</ListView>
</LinearLayout>
colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="white">#FFFFFFFF</color>
<color name="transparency">#00000000</color>
<color name="title_bg">#1C86EE</color>
<color name="end_color">#A0cfef83</color>
<color name="black">#464646</color>
</resources>
MainActivity.xml
package com.ling.customlist;
import java.util.ArrayList;
import java.util.HashMap;
import xb.customlist.R;
import Android.R.array;
import android.app.Activity;
import Android.os.Bundle;
import android.widget.ArrayAdapter;
import Android.widget.ListView;
import android.widget.SimpleAdapter;
public class MainActivity extends Activity {
ListView list;
String data[] = new String[]{
"China","UK","USA","Japan","German","Canada","ET","Narotu"
};
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
list =(ListView) findViewById(R.id.list);
SimpleAdapter adapter = new SimpleAdapter(this, getData(), R.layout.list_item,
new String[]{"title","img"}, new int[]{R.id.title,R.id.img});
list.setAdapter(adapter);
}
private ArrayList<HashMap<String, Object>> getData() {
ArrayList<HashMap<String, Object>> dlist = new ArrayList<HashMap<String,Object>>();
for(int i =0;i<data.length;i++){
HashMap<String, Object>map = new HashMap<String, Object>();
map.put("title", data[i]);
map.put("img", R.drawable.item_left2);
dlist.add(map);
}
return dlist;
}
}