1. 程式人生 > >閱讀郭林《第一行程式碼》的筆記——第3章 軟體也要拼臉蛋,UI開發的點點滴滴

閱讀郭林《第一行程式碼》的筆記——第3章 軟體也要拼臉蛋,UI開發的點點滴滴

一、常見控制元件的使用方法

使用android:layout_width指定了控制元件的寬度,
使用android:layout_height指定了控制元件的高度
Android中所有的控制元件都具有這兩個屬性,可選值有三種match_parent、fill_parent和wrap_content,其中match_parent和fill_parent的意義相同,現在官方更加推薦使用match_parent。match_parent表示讓當前控制元件的大小和父佈局的大小一樣,也就是由父佈局來決定當前控制元件的大小。wrap_content表示讓當前控制元件的大小能夠剛好包含住裡面的內容,也就是由控制元件內容決定當前控制元件的大小。

Android控制元件的可見屬性。所有的Android控制元件都具有這個屬性,可以通過android:visibility進行指定,可選值有三種,visible、invisible和gone。visible表示控制元件是可見的,這個值是預設值,不指定android:visibility時,控制元件都是可見的。invisible表示控制元件不可見,但是它仍然佔據著原來的位置和大小,可以理解成控制元件變成透明狀態了。gone則表示控制元件不僅不可見,而且不再佔用任何螢幕空間。我們還可以通過程式碼來設定控制元件的可見性,使用的是setVisibility()方法,可以傳入View.VISIBLE、View.INVISIBLE和View.GONE三種值。

android:background用於為佈局或控制元件指定一個背景,可以使用顏色或圖片來進行填充。

1、TextView

主要用於在介面上顯示一段文字資訊。
android:gravity=”center”//指定文字的對齊方式

使用android:gravity來指定文字的對齊方式,可選值有top、bottom、left、right、center等,可以用“|”來同時指定多個值,這裡我們指定的”center”,效果等同於”center_vertical|center_horizontal”,表示文字在垂直和水平方向都居中對齊。

android:textSize=”24sp”//指定文字的大小

android:textColor=”#00ff00”//指定文字的顏色

當然TextView中還有很多其他的屬性,這裡我就不再一一介紹了,需要用到的時候去查閱文件就可以了。

2、Button

Button是程式用於和使用者進行互動的一個重要控制元件。

然後我們可以在MainActivity中為Button的點選事件註冊一個監聽器,如下所示:

public class MainActivity extends Activity {

    private Button button;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // 在此處新增邏輯
            }
        });
    }


}

這樣每當點選按鈕時,就會執行監聽器中的onClick()方法,我們只需要在這個方法中加入待處理的邏輯就行了。如果你不喜歡使用匿名類的方式來註冊監聽器,也可以使用實現介面的方式來進行註冊,程式碼如下所示:

public class MainActivity extends Activity implements OnClickListener {

    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.button:
            // 在此處新增邏輯
            break;
        default:
            break;
        }
    }


}

這兩種寫法都可以實現對按鈕點選事件的監聽,至於使用哪一種就全憑你喜好了。

3、EditText

EditText是程式用於和使用者進行互動的另一個重要控制元件,它允許使用者在控制元件裡輸入和編輯內容,並可以在程式中對這些內容進行處理。EditText的應用場景應該算是非常普遍了,發簡訊、發微博、聊QQ等等。

可以看到,EditText中顯示了一段提示性文字,然後當我們輸入任何內容時,這段文字就會自動消失。不過隨著輸入的內容不斷增多,EditText會被不斷地拉長。這時由於EditText的高度指定的是wrap_content,因此它總能包含住裡面的內容,但是當輸入的內容過多時,介面就會變得非常難看。我們可以使用android:maxLines屬性來解決這個問題。

android:maxLines=”2”//指定了EditText的最大行數為兩行,這樣當輸入的內容超過兩行時,文字就會向上滾動,而EditText則不會再繼續拉伸

4、ImageView

ImageView是用於在介面上展示圖片的一個控制元件,通過它可以讓我們的程式介面變得更加豐富多彩。

android:src=”@drawable/ic_launcher”//給ImageView指定了一張圖片

5、ProgressBar

ProgressBar用於在介面上顯示一個進度條,表示我們的程式正在載入一些資料。

style=”?android:attr/progressBarStyleHorizontal”//執行ProgressBar的樣式為水平進度條

android:max=”100”//設定水平進度條的最大值

ProgressBar還有幾種其他的樣式,你可以自己去嘗試一下。

6、AlertDialog

AlertDialog可以在當前的介面彈出一個對話方塊,這個對話方塊是置頂於所有介面元素之上的,能夠遮蔽掉其他控制元件的互動能力,因此一般AlertDialog都是用於提示一些非常重要的內容或者警告資訊。比如為了防止使用者誤刪重要內容,在刪除前彈出一個確認對話方塊。

AlertDialog.Builder dialog = new AlertDialog.Builder (MainActivity.this);//通過AlertDialog.Builder創建出一個AlertDialog的例項
dialog.setTitle("This is Dialog");//設定對話方塊的標題
dialog.setMessage("Something important.");//設定對話方塊的內容
dialog.setCancelable(false);//設定對話方塊是否可以取消
dialog.setPositiveButton("OK", new DialogInterface. OnClickListener() {//為對話方塊設定確定按鈕的點選事件
      @Override
      public void onClick(DialogInterface dialog, int which) {
       }
   });
dialog.setNegativeButton("Cancel", new DialogInterface. OnClickListener() {//為對話方塊設定取消按鈕的點選事件
       @Override
       public void onClick(DialogInterface dialog, int which) {
       }
   });
 dialog.show();//顯示對話方塊

7、ProgressDialog

ProgressDialog和AlertDialog有點類似,都可以在介面上彈出一個對話方塊,都能夠遮蔽掉其他控制元件的互動能力。不同的是,ProgressDialog會在對話方塊中顯示一個進度條,一般是用於表示當前操作比較耗時,讓使用者耐心地等待。

ProgressDialog progressDialog = new ProgressDialog (MainActivity.this);//新建一個ProgressDialog物件
progressDialog.setTitle("This is ProgressDialog");//設定對話方塊的標題
progressDialog.setMessage("Loading...");//設定對話方塊的內容
progressDialog.setCancelable(true);//設定對話方塊是否可以取消
   progressDialog.show();//顯示對話方塊

二、詳解四種基本佈局

佈局是一種可用於放置很多控制元件的容器,它可以按照一定的規律調整內部控制元件的位置,從而編寫出精美的介面。當然,佈局的內部除了放置控制元件外,也可以放置佈局,通過多層佈局的巢狀,我們就能夠完成一些比較複雜的介面實現,示意圖3.15很好地展示了它們之間的關係。
佈局與控制元件的關係

1、LinearLayout

LinearLayout又稱作線性佈局,是一種非常常用的佈局。正如它名字所描述的一樣,這個佈局會將它所包含的控制元件線上性方向上依次排列。

android:orientation屬性:指定佈局的排列方向,有兩個值,分別是horizontal(水平)和vertical(垂直)

這裡需要注意,如果LinearLayout的排列方向是horizontal,內部的控制元件就絕對不能將寬度指定為match_parent,因為這樣的話單獨一個控制元件就會將整個水平方向佔滿,其他的控制元件就沒有可放置的位置了。同樣的道理,如果LinearLayout的排列方向是vertical,內部的控制元件就不能將高度指定為match_parent。

首先來看android:layout_gravity屬性,它和我們上一節中學到的android:gravity屬性看起來有些相似,這兩個屬性有什麼區別呢?其實從名字上就可以看出,android:gravity是用於指定文字在控制元件中的對齊方式,而android:layout_gravity是用於指定控制元件在佈局中的對齊方式。android:layout_gravity的可選值和android:gravity差不多,但是需要注意,當LinearLayout的排列方向是horizontal時,只有垂直方向上的對齊方式才會生效,因為此時水平方向上的長度是不固定的,每新增一個控制元件,水平方向上的長度都會改變,因而無法指定該方向上的對齊方式。同樣的道理,當LinearLayout的排列方向是vertical時,只有水平方向上的對齊方式才會生效。

接下來我們學習下LinearLayout中的另一個重要屬性,android:layout_weight。這個屬性允許我們使用比例的方式來指定控制元件的大小,它在手機螢幕的適配性方面可以起到非常重要的作用。
例子:

<EditText
        android:id="@+id/input_message"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:hint="Type something"
        />

    <Button
        android:id="@+id/send"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Send"
        />

你會發現,這裡竟然將EditText和Button的寬度都指定成了0,這樣文字編輯框和按鈕還能顯示出來嗎?不用擔心,由於我們使用了android:layout_weight屬性,此時控制元件的寬度就不應該再由android:layout_width來決定,這裡指定成0是一種比較規範的寫法。

2、RelativeLayout

RelativeLayout又稱作相對佈局,也是一種非常常用的佈局。和LinearLayout的排列規則不同,RelativeLayout顯得更加隨意一些,它可以通過相對定位的方式讓控制元件出現在佈局的任何位置。也正因為如此,RelativeLayout中的屬性非常多,不過這些屬性都是有規律可循的,其實並不難理解和記憶。

android:layout_alignParentLeft——讓一個控制元件 和父元件的左邊對齊
android:layout_alignParentTop——讓一個控制元件和父元件的頂部對齊
android:layout_alignParentRight——讓一個控制元件 和父元件的右邊對齊
android:layout_alignParentBottom——讓一個控制元件 和父元件的底部對齊
android:layout_centerInParent——讓一個控制元件 居中顯示
這幾個屬性都是相對於父佈局進行定位的。
android:layout_above——讓一個控制元件位於另一個控制元件的上方
android:layout_below——讓一個控制元件位於另一個控制元件的下方
android:layout_toLeftOf——讓一個控制元件位於另一個控制元件的左側
android:layout_toRightOf——讓一個控制元件位於另一個控制元件的右側
這幾個屬性都是控制元件相對於空間進行定位的。
android:layout_alignLeft——讓一個控制元件的左邊緣和另一個控制元件的左邊緣對齊
android:layout_alignRight——讓一個控制元件的右邊緣和另一個控制元件的右邊緣對齊
android:layout_alignTop——讓一個控制元件的上邊緣和另一個控制元件的上邊緣對齊
android:layout_alignBottom——讓一個控制元件的下邊緣和另一個控制元件的下邊緣對齊
這幾個屬性都是相對於控制元件進行定位的。

3、FrameLayout

rameLayout相比於前面兩種佈局就簡單太多了,因此它的應用場景也少了很多。這種佈局沒有任何的定位方式,所有的控制元件都會擺放在佈局的左上角。

4、TableLayout

TableLayout允許我們使用表格的方式來排列控制元件,這種佈局也不是很常用,你只需要瞭解一下它的基本用法就可以了。既然是表格,那就一定會有行和列,在設計表格時我們儘量應該讓每一行都擁有相同的列數,這樣的表格也是最簡單的。不過有時候事情並非總會順從我們的心意,當表格的某行一定要有不相等的列數時,就需要通過合併單元格的方式來應對。

在TableLayout中每加入一個TableRow就表示在表格中添加了一行,然後在TableRow中每加入一個控制元件,就表示在該行中加入了一列,TableRow中的控制元件是不能指定寬度的。不過使用android:stretchColumns屬性就可以很好地解決這個問題,它允許將TableLayout中的某一列進行拉伸,以達到自動適應螢幕寬度的作用。

android:stretchColumns=”1”//這裡將android:stretchColumns的值指定為1,表示如果表格不能完全佔滿螢幕寬度,就將第二列進行拉伸。沒錯!指定成1就是拉伸第二列,指定成0就是拉伸第一列,不要以為這裡我寫錯了哦。

Android中其實還有一個AbsoluteLayout,不過這個佈局官方已經不推薦使用了,因此我們直接將它忽略就好。

三、系統控制元件不夠用?建立自定義控制元件

控制元件和佈局的繼承結構
控制元件和佈局的繼承結構

可以看到,我們所用的所有控制元件都是直接或間接繼承自View的,所用的所有佈局都是直接或間接繼承自ViewGroup的。View是Android中一種最基本的UI元件,它可以在螢幕上繪製一塊矩形區域,並能響應這塊區域的各種事件,因此,我們使用的各種控制元件其實就是在View的基礎之上又添加了各自特有的功能。而ViewGroup則是一種特殊的View,它可以包含很多的子View和子ViewGroup,是一個用於放置控制元件和佈局的容器。

引入佈局
例子: 使用這種方式,不管有多少佈局需要新增標題欄,只需一行include語句就可以了。

建立自定義控制元件
引入佈局的技巧確實解決了重複編寫佈局程式碼的問題,但是如果佈局中有一些控制元件要求能夠響應事件,我們還是需要在每個活動中為這些控制元件單獨編寫一次事件註冊的程式碼。比如說標題欄中的返回按鈕,其實不管是在哪一個活動中,這個按鈕的功能都是相同的,即銷燬掉當前活動。而如果在每一個活動中都需要重新註冊一遍返回按鈕的點選事件,無疑又是增加了很多重複程式碼,這種情況最好是使用自定義控制元件的方式來解決。

例子:
新建TitleLayout繼承自LinearLayout,讓它成為我們自定義的標題欄控制元件,程式碼如下所示:

public class TitleLayout extends LinearLayout {

    public TitleLayout(Context context, AttributeSet attrs) {//重寫了LinearLayout中的帶有兩個引數的建構函式,在佈局中引入TitleLayout控制元件就會呼叫這個建構函式
        super(context, attrs);
        LayoutInflater.from(context).inflate(R.layout.title, this);
    }

}

在建構函式中需要對標題欄佈局進行動態載入,這就要藉助LayoutInflater來實現了。通過LayoutInflater的from()方法可以構建出一個LayoutInflater物件,然後呼叫inflate()方法就可以動態載入一個佈局檔案,inflate()方法接收兩個引數,第一個引數是要載入的佈局檔案的id,這裡我們傳入R.layout.title,第二個引數是給載入好的佈局再新增一個父佈局,這裡我們想要指定為TitleLayout,於是直接傳入this。

現在自定義控制元件已經建立好了,然後我們需要在佈局檔案中新增這個自定義控制元件,修改activity_main.xml中的程式碼,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.example.uicustomviews.TitleLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ></com.example.uicustomviews.TitleLayout>

</LinearLayout>

新增自定義控制元件和新增普通控制元件的方式基本是一樣的,只不過在新增自定義控制元件的時候我們需要指明控制元件的完整類名,包名在這裡是不可以省略的。

重新執行程式,你會發現此時效果和使用引入佈局方式的效果是一樣的。

然後我們來嘗試為標題欄中的按鈕註冊點選事件,修改TitleLayout中的程式碼,如下所示:

public class TitleLayout extends LinearLayout {

    public TitleLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        LayoutInflater.from(context).inflate(R.layout.title, this);
        Button titleBack = (Button) findViewById(R.id.title_back);
        Button titleEdit = (Button) findViewById(R.id.title_edit);
        titleBack.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                ((Activity) getContext()).finish();
            }
        });
        titleEdit.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getContext(), "You clicked Edit button",

                         Toast.LENGTH_SHORT).show();
            }
        });
    }

}

首先還是通過findViewById()方法得到按鈕的例項,然後分別呼叫setOnClickListener()方法給兩個按鈕註冊了點選事件,當點選返回按鈕時銷燬掉當前的活動,當點選編輯按鈕時彈出一段文字。這樣的話,每當我們在一個佈局中引入TitleLayout,返回按鈕和編輯按鈕的點選事件就已經自動實現好了,也是省去了很多編寫重複程式碼的工作。

四、最常用和最難用的控制元件——ListView

ListView絕對可以稱得上是Android中最常用的控制元件之一,幾乎所有的應用程式都會用到它。由於手機螢幕空間都比較有限,能夠一次性在螢幕上顯示的內容並不多,當我們的程式中有大量的資料需要展示的時候,就可以藉助ListView來實現。ListView允許使用者通過手指上下滑動的方式將螢幕外的資料滾動到螢幕內,同時螢幕上原有的資料則會滾動出螢幕。相信你其實每天都在使用這個控制元件,比如檢視手機聯絡人列表,翻閱微博的最新訊息等等。

1、ListView的簡單用法

public class MainActivity extends Activity {

    private String[] data = { "Apple", "Banana", "Orange", "Watermelon",
            "Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango" };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                MainActivity.this, android.R.layout.simple_list_item_1, data);
        ListView listView = (ListView) findViewById(R.id.list_view);
        listView.setAdapter(adapter);
    }

}

既然ListView是用於展示大量資料的,那我們就應該先將資料提供好。這些資料可以是從網上下載的,也可以是從資料庫中讀取的,應該視具體的應用程式場景來決定。
不過,陣列中的資料是無法直接傳遞給ListView的,我們還需要藉助介面卡來完成。Android中提供了很多介面卡的實現類,其中我認為最好用的就是ArrayAdapter。它可以通過泛型來指定要適配的資料型別,然後在建構函式中把要適配的資料傳入即可。ArrayAdapter有多個建構函式的過載,你應該根據實際情況選擇最合適的一種。這裡由於我們提供的資料都是字串,因此將ArrayAdapter的泛型指定為String,然後在ArrayAdapter的建構函式中依次傳入當前上下文、ListView子項佈局的id,以及要適配的資料。注意我們使用了android.R.layout.simple_list_item_1作為ListView子項佈局的id,這是一個Android內建的佈局檔案,裡面只有一個TextView,可用於簡單地顯示一段文字。這樣介面卡物件就構建好了。
最後,還需要呼叫ListView的setAdapter()方法,將構建好的介面卡物件傳遞進去,這樣ListView和資料之間的關聯就建立完成了。
可以通過滾動的方式來檢視螢幕外的資料。

2、定製ListView的介面

——例子見原書3.5.2——

3、提升ListView的執行效率

之所以說ListView這個控制元件很難用,就是因為它有很多的細節可以優化,其中執行效率就是很重要的一點。目前我們ListView的執行效率是很低的,因為在FruitAdapter的getView()方法中每次都將佈局重新載入了一遍,當ListView快速滾動的時候這就會成為效能的瓶頸。
仔細觀察,getView()方法中還有一個convertView引數,這個引數用於將之前載入好的佈局進行快取,以便之後可以進行重用。

View view;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, null);
        } else {
            view = convertView;
        }

可以看到,現在我們在getView()方法中進行了判斷,如果convertView為空,則使用LayoutInflater去載入佈局,如果不為空則直接對convertView進行重用。這樣就大大提高了ListView的執行效率,在快速滾動的時候也可以表現出更好的效能。
不過,目前我們的這份程式碼還是可以繼續優化的,雖然現在已經不會再重複去載入佈局,但是每次在getView()方法中還是會呼叫View的findViewById()方法來獲取一次控制元件的例項。我們可以藉助一個ViewHolder來對這部分效能進行優化,修改FruitAdapter中的程式碼,如下所示:

public class FruitAdapter extends ArrayAdapter<Fruit> {
    ……
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Fruit fruit = getItem(position);
        View view;
        ViewHolder viewHolder;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, null);
            viewHolder = new ViewHolder();
            viewHolder.fruitImage = (ImageView) view.findViewById (R.id.fruit_image);
            viewHolder.fruitName = (TextView) view.findViewById (R.id.fruit_name);
            view.setTag(viewHolder); // 將ViewHolder儲存在View中
        } else {
            view = convertView;
            viewHolder = (ViewHolder) view.getTag(); // 重新獲取ViewHolder
        }
        viewHolder.fruitImage.setImageResource(fruit.getImageId());
        viewHolder.fruitName.setText(fruit.getName());
        return view;
    }

    class ViewHolder {
        ImageView fruitImage;
        TextView fruitName;
    }
}

我們新增了一個內部類ViewHolder,用於對控制元件的例項進行快取。當 convertView為空的時候,建立一個ViewHolder物件,並將控制元件的例項都存放在ViewHolder裡,然後呼叫View的setTag()方法,將ViewHolder物件儲存在View中。當 convertView不為空的時候則呼叫View的getTag()方法,把ViewHolder重新取出。這樣所有控制元件的例項都快取在了ViewHolder裡,就沒有必要每次都通過 findViewById()方法來獲取控制元件例項了。
通過這兩步的優化之後,我們ListView的執行效率就已經非常不錯了。

4、ListView的點選事件

public class MainActivity extends Activity {

    private List<Fruit> fruitList = new ArrayList<Fruit>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initFruits();
        FruitAdapter adapter = new FruitAdapter(MainActivity.this, R.layout.fruit_item, fruitList);
        ListView listView = (ListView) findViewById(R.id.list_view);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                Fruit fruit = fruitList.get(position);
                Toast.makeText(MainActivity.this, fruit.getName(),
                        Toast.LENGTH_SHORT).show();
            }
        });
    }
     ……
}

可以看到,我們使用了setOnItemClickListener()方法來為ListView註冊了一個監聽器,當用戶點選了ListView中的任何一個子項時就會回撥onItemClick()方法,在這個方法中可以通過position引數判斷出使用者點選的是哪一個子項,然後獲取到相應的水果,並通過Toast將水果的名字顯示出來。

五、單位和尺寸

在佈局檔案中指定寬高的固定大小有以下常用單位可供選擇:px、pt、dp和sp。

px和pt的窘境
px是畫素的意思,即螢幕中可以顯示的最小元素單元,我們應用裡任何可見的東西都是由一個個畫素點組成的。單獨一個畫素點非常的微小,肉眼是無法看見的,可是當許許多多的畫素點聚集到一起時,就可以拼接成五彩繽紛的圖案。

pt是磅數的意思,1磅等於1/72英寸,一般pt都會作為字型的單位來使用。

過去在PC上使用px和pt的時候可以說是非常得心應手,能把程式打扮得漂漂亮亮。可是現在到了手機上,這兩個單位就顯得有些力不從心了,因為手機的解析度各不相同,一個200px寬的按鈕在低解析度的手機上可能將近佔據滿屏,而到了高解析度的手機上可能只佔據螢幕的一半。

dp和sp來幫忙
谷歌當然也意識到了這個令人頭疼了問題,於是為Android引入了一套新的單位dp和sp。

dp是密度無關畫素的意思,也被稱作dip,和px相比,它在不同密度的螢幕中的顯示比例將保持一致。

sp是可伸縮畫素的意思,它採用了和dp同樣的設計理念,解決了文字大小的適配問題。

什麼叫密度?Android中的密度就是螢幕每英寸所包含的畫素數,通常以dpi為單位。比如一個手機螢幕的寬是2英寸長是3英寸,如果它的解析度是320*480畫素,那這個螢幕的密度就是160dpi,如果它的解析度是640*960,那這個螢幕的密度就是320dpi,因此密度值越高的螢幕顯示的效果就越精細。我們可以通過程式碼來得知當前螢幕的密度值是多少,修改MainActivity中的程式碼,如下所示:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        float xdpi = getResources().getDisplayMetrics().xdpi;
        float ydpi = getResources().getDisplayMetrics().ydpi;
//動態獲取到了當前螢幕的密度值
        Log.d("MainActivity", "xdpi is " + xdpi);
        Log.d("MainActivity", "ydpi is " + ydpi);
    }

}

根據Android的規定,在160dpi的螢幕上,1dp等於1px,而在320dpi的螢幕上,1dp就等於2px。因此,使用dp來指定控制元件的寬和高,就可以保證控制元件在不同密度的螢幕中的顯示比例保持一致。

sp的原理和dp是一樣的,它主要是用於指定文字的大小,這裡就不再進行介紹了。
總結一下,在編寫Android程式的時候,儘量將控制元件或佈局的大小指定成match_parent或wrap_content,如果必須要指定一個固定值,則使用dp來作為單位,指定文字大小的時候使用sp作為單位。

六、製作Nine-Patch圖片

.9圖片是一種被特殊處理過的png圖片,能夠指定哪些區域可以被拉伸而哪些區域不可以。

在Android sdk目錄下有一個tools資料夾,在這個資料夾中找到draw9patch.bat檔案,我們就是使用它來製作Nine-Patch圖片的。

我們可以在圖片的四個邊框繪製一個個的小黑點,在上邊框和左邊框繪製的部分就表示當圖片需要拉伸時就拉伸黑點標記的區域,在下邊框和右邊框繪製的部分則表示內容會被放置的區域。

左側和頂部是控制拉伸區域,右側和底部是可能控制顯示的內容區域。

相關推薦

閱讀第一程式碼》的筆記——3 軟體臉蛋UI開發點點滴滴

一、常見控制元件的使用方法 使用android:layout_width指定了控制元件的寬度, 使用android:layout_height指定了控制元件的高度 Android中所有的控制元件都具有這兩個屬性,可選值有三種match_pare

第二程式碼學習筆記——:軟體臉蛋——UI開發點點滴滴

本章要點 使用Android提供的UI來編寫程式介面。本章的內容就是學習UI方面的知識。 3.1 如何編寫程式介面 Android種編寫程式介面的方式: 1. 視覺化編輯器(不推薦) 2. 編寫XML程式碼(推薦) 3.2 常用控制元

第一程式碼:全域性大喇叭 筆記(基於Android8.0)

由於Android8.0對廣播機制做了很大的調整理,導致《第一行程式碼》中很多例項無法正常執行,因此我結合書本,自行整理了一下。 廣播需要接收器和傳送器。系統的動作都會發送一條廣播,例如電量的變化,系

Android《第一程式碼5 筆記

第五章主要介紹了Android中的廣播機制。 Android中的每個應用程式都可以對自己感興趣的廣播進行註冊。Android允許應用程式自由地傳送和接收廣播。可以通過Intent傳送廣播,通過廣播接收器(Broadcast Receiver)來接收廣播。 廣播型別分為標準廣

第一程式碼——軟體臉蛋——UI開發點點滴滴

目錄: 3.1 如何編寫程式介面 3.2 常用控制元件的使用方法 3.2.1TextView 3.2.2 Button 3.2.3 EditText 3.2.4 ImageView 3.2.5 ProgressBar 3.2.6 Al

第一程式碼 SQLite資料庫儲存——win10配置adb環境變數及檢視Book表

首先我們需配置adb環境變數。右擊電腦,選擇屬性,出現下面的介面選擇高階系統設定,選擇環境變數,在這裡選擇系統變數裡的Path路徑,點選編輯按鈕接著點選新建按鈕,然後直接將platform-tools的路徑加入進來,點選確定。其中platform-tools在安裝Androi

第一程式碼+Android+2版 筆記

Android四大元件: 1活動(Activity):應用程式的門面,即在應用中看得到的東西; 2服務(Service):執行在後臺,即使使用者退出了應用,服務仍然是可以繼續執行的; 3廣播接收器(BroadcastReceiver):接收和發出電話、簡訊等訊息; 4內容提

第一程式碼 Android 2版》下載

2018年11月02日 14:08:44 無人寵 @ 閱讀數:3 標籤: 程式設計 資料 區塊

第二程式碼學習筆記——:手機平板相容——探究碎片

本章要點 作為一名專業的Android開發人員,能夠同時相容手機和平板的開發時我們必須要做到的事情。 4.1 碎片是什麼 碎片(Fragment)是一種可以巢狀在活動當中的UI片段,它能讓程式更加合理和充分的利用大螢幕的控制元件。 4.2

青出於紅——《第一程式碼2版)》

2014年紅色封面的《第一行程式碼》付梓之初便受到不同學習層次尤其是剛入門的Android開發者的熱烈歡迎,被譽為“Android學習的紅寶書”,一時間洛陽紙貴。最近《第一行程式碼(第二版)》在作

(第一程式碼筆記)活動的4種啟動模式詳解

singleInstance模式應該算是四種啟動模式中最特殊也最複雜的一個了,你也需要多花點功夫來理解這個模式。不同於以上三種啟動模式,指定為singleInstance模式的活動會啟用一個新的返回棧來管理這個活動(其實如果singleTask模式指定了不同的taskAffinity,也會啟動一個新的返回棧

第一程式碼筆記9(通知的基本用法)

1.通知可以再活動、廣播接收器、服務裡建立  在活動中建立通知的場景比較少見,因為一般只有程式進入後臺的時候我們才需要使用到通知 2.PendingIntent和Intent  相同點:他們都可以指明某一個“意圖”,都可以用來啟動活動、啟動服務以及傳送廣播 不同點:Inte

第一程式碼筆記系列-廣播1)android 廣播動態註冊和靜態註冊有什麼區別及基本用法

新建一個BroadcastTest專案,然後修改MainActivity中的程式碼,如下所示: public class MainActivity extends Activity { private IntentFilter intentFilter; private NetworkChange

Javascript權威指南閱讀筆記--3類型、值和變量(1)

分享圖片 自動 局部變量 清理 ace defined define 原型 未在   之前一直有個想法,好好讀完JS權威指南,便於自己對於JS有個較為全面的了解。畢竟本人非計算機專業出生,雖然做著相關行業的工作,但總覺得對於基礎的掌握並沒有相關專業學者紮實,正好因為辭職待業

第一代碼12-1.標題欄

toolbar rri 樂趣 soft class 創建 end length switch 今天學校停電,沒意思,特來更新兩篇文章,讀了第一行代碼之後,覺得內容寫的非常不錯,於是照著書把代碼敲了一遍,今天敲的是Toolbar。 Toolbar就是標題欄,只不過之前使用的標

程式碼整潔之道 讀書筆記 - 3 函式

短小 函式的第一規則是要短小。第二條規則是還要更短小。 函式20行封頂最佳。 if語句、else語句、while語句等,其中的程式碼塊應該只有一行,而且,塊內呼叫的函式擁有較具說明性的名稱,還能起到文件的作用。 只做一件事 函式應該做一件事。做好這件事。只做這一件事。 每個函式一個抽象層級 自頂

第一本Docker書》學習筆記——3 Docker入門

應用程序 接受 inter ipad 此外 cannot settings info 為我 3.1 確保Docker已經就緒 查看docker是否正常工作: sudo docker info 3.2 運行我們的第一個容器 現在,讓我們嘗試啟動第一個Docker容器。我們可以

閱讀徐宜生《Android群英傳》的筆記——3 Android控制元件架構與自定義控制元件詳解(3.6-3.8)

3.6 自定義 View 在自定義 View 時,我們通常會去重寫 onDraw() 方法來繪製 View 的顯示內容。如果該 View 還需要使用 wrap_content 屬性,那麼還必須重寫 onMeasure() 方法。另外,通過自定義 attr

Unity Shader入門精學習筆記 - 3 Unity Shader 基礎

但是 detail spa net 表示 part 文件 人的 text 來源作者:candycat http://blog.csdn.net/candycat1992/article/ 概述 總體來說,在Unity中我們需要配合使用材質和Unity Shader才能達

EffictiveC++筆記 3

個數 管理器 剔除 del 不能 會有 AR ati ffi 我根據自己的理解,對原文的精華部分進行了提煉,並在一些難以理解的地方加上了自己的“可能比較準確”的「翻譯」。 Chapter 3 資源管理 條款13: 以對象管理資源 有時即使你順利地寫了對應對象的delet