乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      改變Android按鈕背景顏色的高效方法 – 碼農(nóng)網(wǎng)

       quasiceo 2016-01-11


      本文將介紹一種有效改變Android按鈕顏色的方法。

      按鈕可以在狀態(tài)改變時改變其顏色(例如按下,禁用,高亮顯示)。但是,這需要一一說明每個狀態(tài)。這篇文章將提供你一個根據(jù)狀態(tài)變化輕松改變按鈕顏色的方法。如果你正在寫自定義視圖,那么不妨也來讀一讀,因為中間我會涉及到如何用自定義屬性實現(xiàn)自定義視圖的相關(guān)內(nèi)容。

      如何實現(xiàn)

      Android提供了靈活的繪制選擇機制,可根據(jù)視圖狀態(tài)轉(zhuǎn)變視圖外觀。每個狀態(tài)通過一個單獨的部分而存在。例如:在正常、禁用、按下、高亮狀態(tài)下的按鈕有著不同的背景顏色。請看下面的代碼示例:

      button_1_background.xml

      <selector xmlns:android="http://schemas./apk/res/android">
      <!&mdash; pressed state -->
      <item android:drawable="@drawable/button_1_selected" android:state_pressed="true"/>
      <!-- focused state -->
      <item android:drawable="@drawable/button_1_focused" android:state_focused="true"/>
      <!-- default state -->
      <item android:drawable="@drawable/button_1_normal"/>
      </selector>

      每個狀態(tài)drawables的屬性(button_1_selectedbutton_1_focused,button_1_normal)必須定義在相應的在drawables目錄下:

      button_1_normal.xml

      <shape xmlns:android="http://schemas./apk/res/android">
          <solid android:color="@color/button_1_normal_background"/>
          <corners android:radius="10dip"/>
      </shape>

      button_1_focused.xml

      <shape xmlns:android="http://schemas./apk/res/android">
          <solid android:color="@color/button_1_focused_background"/>
          <corners android:radius="10dip"/>
      </shape>

      button_1_selected.xml

      <shape xmlns:android="http://schemas./apk/res/android">
          <solid android:color="@color/button_1_selected_background"/>
          <corners android:radius="10dip"/>
      </shape>

      然后設置按鈕背景:

      android:background="@drawable/button_1_background"

      這種方法非常靈活。但是,當你的app有許多按鈕,而每個按鈕的顏色又各不相同時,維護每個按鈕的上述所有XML文件就會變得異常困難起來。如果你改變正常狀態(tài)的按鈕顏色,那么你必須改變其他狀態(tài)的顏色。在上面的例子中,每個按鈕需要4個XML文件。那么如果你的應用程序有10個或更多個按鈕呢?

      為了清楚說明我的意思,請看下面的截圖:

       main screen.

       send screen.

      這些截圖來自于一款免費產(chǎn)品BMEX。

      這兩張圖片分別是app的主屏幕和發(fā)送屏幕。兩個屏幕都采用了Metro風格。每個屏幕都有6個不同顏色的按鈕。并且按鈕的顏色會根據(jù)狀態(tài)的改變而改變。共計12個按鈕,所以我們需要12個drawable selector XML文件和24個drawable state XML文件。并且隨著app的發(fā)展,軟件還得允許新的屏幕和新的按鈕的添加。維護這些內(nèi)容可不是一項簡單的任務。

      為了使過程更加簡單和高效,我們另尋了一種更有效的解決方案——并且已經(jīng)實現(xiàn)在自定義按鈕視圖中。這是一個容易初始化的按鈕。我們稱之為RoundButton,因為它支持圓角。

      在另一個產(chǎn)品中,我們需要高亮功能,但是,又不想因此單獨創(chuàng)建自定義視圖。所以,我們把它添加到RoundButton中。請看下面的截圖:

       highlighed.

      正如你所見,我們可以選擇也可以不選屏幕上的按鈕(頂部的列表圖表和每個元素后面的添加圖標)。當按鈕被選中后,它的highlighted狀態(tài)就被設置為true,反之,則為false。并且按鈕的外觀會作適當改變。在上面的例子中,高亮模式使用了“image”。在這種模式下,圖像的可見象素會被繪制為高亮顏色。

      首先,我們?yōu)镽oundButton定義屬性集。這是一組可以通過布局XML設置的屬性。

      attrs_round_button.xml

      <resources>
      
          <declare-styleable name="RoundButton">
              <attr name="image" format="reference"/>
              <attr name="bgcolor" format="color"/>
              <attr name="text" format="string"/>
      
              <attr name="radius" format="float"/>
      
              <attr name="highlightColor" format="color"/>
              <attr name="highlightMode" format="enum">
                  <enum name="none" value="0"/>
                  <enum name="image" value="1"/>
                  <enum name="background" value="2"/>
              </attr>
          </declare-styleable>
      
      </resources>

      我們增加了 imagebgcolor,text,邊框圓角半徑,highlightColor和highlightMode屬性。按下狀態(tài)的顏色會從bgcolor導出(后面會描述的)。

      實現(xiàn)按鈕

      首先,我們需要實現(xiàn)構(gòu)造函數(shù)和解析參數(shù)。我們創(chuàng)建了3個不同的構(gòu)造函數(shù):

      public RoundButton(Context context, AttributeSet attrs, int defStyle) {
      	super(context, attrs, defStyle);
      
      	init(attrs, defStyle);
      }
      
      public RoundButton(Context context, AttributeSet attrs) {
      	super(context, attrs);
      
      	init(attrs, 0);
      }
      
      public RoundButton(Context context) {
      	super(context);
      
      	init(null, 0);
      }

      所有這些構(gòu)造函數(shù)調(diào)用init方法。

      現(xiàn)在,我們需要實現(xiàn)init方法。它將屬性集和默認樣式作為輸入?yún)?shù)。在init方法中,我們獲取屬性值,并初始化內(nèi)部變量。如果屬性集為null,那就使用默認值。

      private void init(AttributeSet attrs, int defStyle) {
      	Drawable image;
      	int bgcolor;
      	String text;
      
      	if (attrs != null) {
      		final TypedArray a = getContext().obtainStyledAttributes(attrs,
      				R.styleable.RoundButton, defStyle, 0);
      
      		image = a.getDrawable(R.styleable.RoundButton_image);
      
      		bgcolor = a.getColor(R.styleable.RoundButton_bgcolor, 0xffffffff);
      
      		text = a.getString(R.styleable.RoundButton_text);
      
      		radius = a.getFloat(R.styleable.RoundButton_radius, 12.0f);
      
      		highlightMode = HighlightMode.getValue(a.getInt
      		(R.styleable.RoundButton_highlightMode, HighlightMode.None.ordinal()));
      
      		highlightColor = a.getColor(R.styleable.RoundButton_highlightColor, 0xff00b5ff);
      
      		a.recycle();
      	}
      	else {
      		image = null;
      
      		text = "";
      
      		bgcolor = 0xff808080;
      
      		radius = 12.0f;
      
      		highlightMode = HighlightMode.None;
      
      		highlightColor = 0xff00b5ff;
      	}
      
      	init(image, bgcolor, text);
      }

      然后,我們創(chuàng)建另一個init方法。這個方法用于創(chuàng)建對象,并需要渲染按鈕的內(nèi)容。 此處的init方法聲明為public,因為創(chuàng)建RoundButton時需要調(diào)用它。它創(chuàng)建了背景和按下時的“噴漆(paint)”——繪制正常和按下狀態(tài)時的背景的對象。按下的顏色選取比bgcolor更亮的顏色。使顏色變亮的的方法,稍后會進行說明。這里初始化了高亮模式。如果背景設置為高亮,那就創(chuàng)建高亮噴漆,用于繪制高亮時的按鈕背景。如果圖像模式設置為高亮,那就創(chuàng)建高亮圖像。在createHighlightImage方法中創(chuàng)建圖像的代碼,之后會一一給出。

      public void init(Drawable image, int bgcolor, String text) {
      	this.image = image;
      
      	bgpaint = new Paint(Paint.ANTI_ALIAS_FLAG);
      	bgpaint.setColor(bgcolor);
      
      	pressedBgpaint = new Paint(Paint.ANTI_ALIAS_FLAG);
      	pressedBgpaint.setColor(brighter(bgcolor));
      
      	if (text == null)
      		text = "";
      
      	this.text = text;
      
      	textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
      	textPaint.setColor(0xffffffff);
      	textPaint.setTextAlign(Paint.Align.CENTER);
      	textPaint.setTextSize(pixelsToSp(getContext(), textSize));
      
      	if (highlightMode == HighlightMode.Background) {
      		highlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
      		highlightPaint.setColor(highlightColor);
      	}
      	else if (highlightMode == HighlightMode.Image) {
      		highlightImage = createHighlightImage();
      	}
      
      	setClickable(true);
      }

      要獲得按下狀態(tài)的色值,我們創(chuàng)建了brighter方法。它將顏色作為參數(shù),并返回比該顏色更亮的顏色。這個方法也很簡單:

      public void init(Drawable image, int bgcolor, String text) {
      	this.image = image;
      
      	bgpaint = new Paint(Paint.ANTI_ALIAS_FLAG);
      	bgpaint.setColor(bgcolor);
      
      	pressedBgpaint = new Paint(Paint.ANTI_ALIAS_FLAG);
      	pressedBgpaint.setColor(brighter(bgcolor));
      
      	if (text == null)
      		text = "";
      
      	this.text = text;
      
      	textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
      	textPaint.setColor(0xffffffff);
      	textPaint.setTextAlign(Paint.Align.CENTER);
      	textPaint.setTextSize(pixelsToSp(getContext(), textSize));
      
      	if (highlightMode == HighlightMode.Background) {
      		highlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
      		highlightPaint.setColor(highlightColor);
      	}
      	else if (highlightMode == HighlightMode.Image) {
      		highlightImage = createHighlightImage();
      	}
      
      	setClickable(true);
      }

      接下來的方法是createHighlightImage。當圖像設置為高亮模式時,它會調(diào)用上面所示的方法。但是開頭有一些比較棘手的代碼。它需要得到圖像的像素。然后處理像素 ——如果像素是不透明的(alpha != 0),就用高亮色值取代它,但是如果像素是透明的,那就不用改動。通過這種操作,我們創(chuàng)建了更高亮的圖像。然后,我們將修改后的像素放回位圖。并且在方法的最后,創(chuàng)建并返回BitmapDrawable。

      private Drawable createHighlightImage() {
      	int width = image.getIntrinsicWidth();
      	int height = image.getIntrinsicHeight();
      
      	Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
      
      	Canvas canvas = new Canvas(bitmap);
      	image.setBounds(0, 0, width, height);
      	image.draw(canvas);
      
      	int count = bitmap.getWidth() * bitmap.getHeight();
      	int pixels[] = new int[count];
      
      	bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
      	for (int n = 0; n < count; n++) {
      		boolean v = (Color.alpha(pixels[n])) != 0;
      
      		if (v) {
      			int pixel = pixels[n];
      
      			int alpha = Color.alpha(pixel);
      			int red = Color.red(highlightColor);
      			int green = Color.green(highlightColor);
      			int blue = Color.blue(highlightColor);
      
      			int color = Color.argb(alpha, red, green, blue);
      
      			pixels[n] = color;
      		}
      	}
      
      	bitmap.setPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
      
      	return new BitmapDrawable(getResources(), bitmap);
      }

      為了處理狀態(tài)變化,我們需要處理觸摸事件。所以需要實現(xiàn)觸摸處理。當我們觸摸按鈕時,它的狀態(tài)就會變?yōu)閜ressed(按下),并重繪按鈕中的內(nèi)容。當按鈕沒有被觸摸,那它的pressed標志就設置為false,并重繪按鈕中的內(nèi)容。

      @Override
      public boolean onTouchEvent(MotionEvent event) {
      	int action = event.getActionMasked();
      
      	switch (action) {
      	case MotionEvent.ACTION_DOWN:
      		pressed = true;
      		invalidate();
      		break;			
      	case MotionEvent.ACTION_UP:
      		pressed = false;
      		invalidate();
      		break;
      	case MotionEvent.ACTION_CANCEL:
      	case MotionEvent.ACTION_OUTSIDE:
      	case MotionEvent.ACTION_HOVER_EXIT:
      		pressed = false;
      		invalidate();
      		break;
      	}
      
      	return super.onTouchEvent(event);
      }

      然后,我們實現(xiàn)onDraw按鈕方法。此方法繪制了按鈕的內(nèi)容。自定義視圖首次展示以及每次重繪時就調(diào)用這個onDraw方法。

      protected void onDraw(Canvas canvas) {
      	RectF bounds = new RectF(0, 0, getWidth(), getHeight());
      
      	Drawable image = null;
      	Paint bgPaint = null;
      
      	switch (highlightMode) {
      	case None:
      		image = this.image;
      		bgPaint = pressed ? pressedBgpaint : this.bgpaint;
      		break;
      	case Background:
      		image = this.image;
      		if (pressed)
      			bgPaint = pressedBgpaint;
      		else 
      			bgPaint = highlighted ? highlightPaint : this.bgpaint;
      		break;
      	case Image:
      		image = highlighted ? highlightImage : this.image;
      		bgPaint = pressed ? pressedBgpaint : this.bgpaint;
      		break;
      	}
      
      	if (radius != 0.0f)
      		canvas.drawRoundRect(bounds, radius, radius, bgPaint);
      	else 
      		canvas.drawRect(bounds, bgPaint);
      
      	Rect textBounds = new Rect();
      	if (text.length() > 0)
      		textPaint.getTextBounds(text, 0, text.length(), textBounds);
      
      	float h_dst = ((image != null) ? image.getMinimumHeight() + 
      	((text.length() > 0) ? spacing : 0) : 0) + textBounds.height();
      
      	float xd = (bounds.width() - ((image != null) ? image.getMinimumWidth() : 0)) / 2;
      	float yd = (bounds.height() - h_dst) / 2; 
      
      	if (image != null) {
      		image.setBounds((int) xd, (int) yd, (int) 
      		(xd + image.getMinimumWidth()), (int) (yd + image.getMinimumHeight()));
      		image.draw(canvas);
      	}
      
      	float xt = (bounds.width() - 0 * textBounds.width()) / 2;
      	float yt = yd + ((image != null) ? image.getMinimumHeight() + 
      	((text.length() > 0) ? spacing : 0) : textBounds.height());// + textBounds.height();
      
      	canvas.drawText(text, xt, yt, textPaint);
      
      	if (checked && checkable && checkedImage != null) {
      		checkedImage.setBounds((int) (bounds.width() - 
      		checkedImage.getMinimumWidth()), (int) (bounds.height() - checkedImage.getMinimumHeight()),
      				(int) bounds.width(), (int) bounds.height());
      		checkedImage.draw(canvas);
      	}
      }

      用法

      為了整合RoundButton到代碼,你需要下載源代碼文件。在源代碼文件中,有Eclipse項目,源代碼和XML資源文件。你可以將它們復制到你的app項目中?;蛘呔幾gRoundButton項目并將其作為庫添加到你的項目。

      如果你使用的是可視化編輯器,那就直接從控件列表中選擇RoundButton,在添加它之后,設置其屬性。

      除了可視化編輯器,RoundButton既可以從布局XML,也可以從代碼中插入。從布局XML添加的話,你可以這么使用。示例如下:

      <RelativeLayout xmlns:android="http://schemas./apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:focusable="false"
          android:focusableInTouchMode="false"
          android:descendantFocusability="blocksDescendants"
          android:orientation="horizontal" 
          xmlns:app="http://schemas./apk/res/com.bitgriff.bamp">
      
         	<com.bitgriff.bamp.helpers.RoundButton
              android:id="@+id/button"
              app:radius="0"
          	app:image="@drawable/ic_addtomedialibrary"
              app:bgcolor="@color/transparent"
              app:highlightMode="image"
              android:layout_width="40dip"
              android:layout_height="80dip"
              android:layout_centerVertical="true"
              android:layout_alignParentRight="true"/>
      
      </RelativeLayout>

      從代碼添加RoundButton,可以創(chuàng)造新的RoundButton實例。調(diào)用它的init方法傳遞圖像(可為null),bgcolo和text。并添加RoundButton到你的viewGroup:

      roundButton = new RoundButton(context);
      roundButton.init(image, bgcolor, text);

      進一步設想

      此外,我們還可以改變RoundButton的形狀。例如,制作圓形按鈕,正如現(xiàn)在很多Android app中所見的那樣。也可能配置圖像位置(left、right、top、bottom)。等等。

      總結(jié)

      這篇文章主要描述了如何實現(xiàn)根據(jù)狀態(tài)改變背景的自定義按鈕。這個簡單的組件能為我們節(jié)省很多時間。希望能對你有用。


        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多