Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android入門——構建UI布局的多種方式

Android入門——構建UI布局的多種方式

編輯:關於Android編程

引言

作為Android App,給人第一印象的就是用戶界面(UI),簡潔友好的UI,自然會給用戶優秀的體驗,自然很容易就得到用戶的認可和贊許,這樣App才變得真正的有價值。所以作為開發App的第一步,UI尤為重要,構建UI有很多種方式:xml靜態布局java動態代碼HTML構建(借助WebView)和第三方開源框架等。

一、構成UI的基本元素——View和ViewGroup概述

在Android中絕大部分的UI組件都是存放在android.widget包及其子包、android.view包及其子包,其中所有的UI視圖組件都是繼承自View類,其實View有點類似Swing編程的JPanel,代表著一個空白的矩形區域。View類還有一個重要的子類ViewGroup,所以它也具有View的特性,但它主要用來充當View的容器,將其中的View視作自己的孩子,對它的子View進行管理,當然它的孩子也可以是ViewGroup類型。但是ViewGroup並不難單獨使用往往是作為其他的組件的容器。值得注意的是Android中的View與我們以前理解的“視圖”不同。在Android中,View比視圖具有更廣的含義,它包含了用戶交互和顯示,更像Windows操作系統中的window。ViewGroup(根節點)和它的孩子們(View和ViewGroup)以樹形結構形成了一個層次結構,View類有接受和處理消息的功能,android系統所產生的消息會在這些ViewGroup和 View之間傳遞。
這裡寫圖片描述

由上圖可見,作為容器的ViewGroup可以包含作為葉子節點的View,也可以包含作為更低層次的子ViewGroup,而子ViewGroup又可以包含下一層的葉子節點的View和ViewGroup。事實上,這種靈活的View層次結構可以形成非常復雜的UI布局,我們也可以據此設計並開發非常精致的UI界面。

二、View和ViewGroup簡介

一般來說,開發Android應用程序的UI時我們都不是直接使用View和ViewGroup,而是使用他們各種的派生類。

View的直接子類:AnalogClock,ImageView,KeyboardView,
ProgressBar,SurfaceView,TextView,ViewGroup,ViewStub

View的間接子類:AbsListView,AbsSeekBar, AbsSpinner, AbsoluteLayout,
AdapterView,AdapterViewAnimator,
AdapterViewFlipper, AppWidgetHostView,
AutoCompleteTextView,Button,CalendarView, CheckBox, CheckedTextView,
Chronometer, CompoundButton

ViewGroup的直接子類:AbsoluteLayout,AdapterView,FragmentBreadCrumbs,FrameLayout,LinearLayout,RelativeLayout,SlidingDrawer

ViewGroup的間接子類:AbsListView,AbsSpinner, AdapterViewAnimator,
AdapterViewFlipper, AppWidgetHostView, CalendarView, DatePicker,
DialerFilter, ExpandableListView, Gallery,
GestureOverlayView,GridView,HorizontalScrollView,
ImageSwitcher,ListView

以上這些所有基類、派生類都是Android framework層集成的標准系統類,開發者在應用開發中可直接引用SDK中這些系統類及其API。當然在很多時候,直接使用這些系統類並不能滿足應用開發的需要,我們還得自己去開發自定義控件來滿足自己的項目需求(這是後話了,以後再總結)。

三、View的常用xml屬性及方法說明

在Android中組件的幾乎所有屬性都提供了兩種方式來控制其行為,所以我們既可以在xml布局中直接靜態賦值,也可以在代碼中通過對應的方法進行動態控制,關系如下:

xml屬性 對應的方法 說明 android:alpha setAlpha(float) 設置組件的透明度(0——1) android:background setBackgroundResource(int) 設置背景 android:clickable setClickable(boolean) 設置是否可以接收點擊事件並觸發 android:duplicateParentState   設置為true的時候可以直接從他直接的父組件中獲取其狀態(focused, pressed, etc.) android:fadeScrollbars setScrollbarFadingEnabled(boolean) 但不使用滾動條時是否淡出顯示滾動條 android:fadingEdgeLength setVerticalFadingEdgeLength() 設置淡出邊界的長度 android:fitsSystemWindows setFitsSystemWindows(boolean) 設置布局適應系統,比如說狀態欄 android:focusable setFocusable(boolean) 是否可獲取焦點 android:id setId(int) 設置Id android:keepScreenOn setKeepScreenOn(boolean) 設置該組件是否會強制手機屏幕一直打開 android:layerType setLayerType(int,Paint) 設置硬件加速 android:layoutDirection setLayoutDirection(int) 設置布局從左向右,或從右向左,etc android:longClickable setLongClickable(boolean) 設置是否可以接收長點擊事件並觸發 android:minHeight/minWidth setMinimumHeight(int)/setMinimumWidth 設置最小高(寬)度 android:nextFocusDownsetNextFocusDownId(int) 設置焦點在該組件上且點擊向下\左\右\上 鍵時獲得焦點的組件Id android:onClick   點擊時觸發的方法 android:paddingsetPadding(int,int,int,int) 設置內邊距 android:rotationsetRotation(float) 設置旋轉角度 android:scaleX/Y setScaleX/Y(float) 水平/垂直方向的縮放比 android:scrollX/Y   初始化後組件的水平/垂直偏移 android:scrollbarSize setScrollBarSize(int) 設置水平滾動條的高度和垂直滾動條的寬度 android:scrollbarStyle setScrollBarStyle(int) 設置滾動條的風格:insideOverlay、insideInset、outSideOverlay、outSideInset android:scrollbarThumbHorizontal   設置滾動條的Drawable對象 android:scrollbars   設置是否顯示滾動條或顯示什麼滾動條 android:soundEffectsEnabled setSoundEffectsEnabled(boolean) 設置組件按下後是否使用音效 android:tag   和Id類似也可通過View.findViewWithTag()獲取 android:textAlignment setTextAlignment(int) 定義文字的對齊方式 android:transformPivotX/Y setPivotX/Y(float) 設置旋轉時的中心坐標X/Y android:translationX/Y/Z setTranslationX/Y/Z(float) 設置位移 android:visibility setVisibility(int) 設置是否可見 android:elevation setElevation(float) 設置該組件“浮”起來的高度,來呈現3D效果,android5.0 Material Design新增的屬性

四、ViewGroup的重要內部類及常用布局、屬性、方法

ViewGroup是一個特殊的View類,它繼承於android.view.View。它的功能就是裝載和管理下一層的View對象和ViewGroup對象。而ViewGroup是布局管理器(layout)及View容器的基類。而且ViewGroup中,還定義了2個內部類:ViewGroup.LayoutParamsViewGroup.MarginLayoutParams。這兩個內部類定義了一個顯示對象的位置、大小等屬性,View還可以通過LayoutParams中的這些屬性值來管理控制布局

1、ViewGroup.LayoutParams和ViewGroup.MarginLayoutParams

ViewGroup.MarginLayoutParams繼承自ViewGroup.LayoutParams

xml屬性 相關方法 說明 android:layout_height   指定該子組件的布局高度 android:layout_width   指定該子組件的布局寬度 ViewGroup.LayoutParams的構造方法 ViewGroup.LayoutParams(Context c, AttributeSet attrs) ViewGroup.LayoutParams(int width, int height) ViewGroup.LayoutParams(ViewGroup.LayoutParams source)

2、Anroid五種布局

FrameLayout:最簡單的一個布局對象。它裡面只顯示一個顯示對象。所有的顯示對象都將會固定在屏幕的左上角,不能指定位置。但允許有多個顯
示對象,但後一個將會直接在前 一個之上進行覆蓋顯示,把前一個部份或全部擋住(除非後一個是透明的)。

LinearLayout:以單一方向對其中的顯示對象進行排列顯示,如以垂直排列顯示,則布局管理器中將只有一列;如以水平排列顯示,則布局管理器中將只有一行。同時,它還可以對個別的顯示對象設置顯示比例。

TableLayout:以擁有任意行列的表格對顯示對象進行布局,每個顯示對象被分配到各自的單元格之中,但單元格的邊框線不可見。

RelativeLayout:允許通過指定顯示對象相對於其它顯示對象或父級對象的相對位置來布局。如一個按鈕可以放於另一個按鈕的左邊,或者可以放在布局管理器的中央。

AbsoluteLayout:允許以坐標的方式,指定顯示對象的具體位置,左上角的坐標為(0, 0),向下及向右,坐標值變大。這種布局管理器由於顯示對象的位置定死了,所以在不同的設備上,有可能會出現最終的顯示效果不一致,基本不用。

五、構建UI布局

1、通過xml靜態布局構建

xml布局最常用,如果可以的話優先考慮xml靜態布局,官方也十分推薦使用這種方式,因為他減弱了代碼和視圖的耦合。

先定義xml布局文件
<code class=" hljs handlebars"><linearlayout 3e--="">
xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"
    android:orientation="vertical">

       <com.crazymo.costompopwindow android:id="" ...="">

       <com.crazymo.costompopwindow>
    <framelayout android:id="@+id/id_content_layout" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1">

</framelayout></com.crazymo.costompopwindow></com.crazymo.costompopwindow></linearlayout></code>
然後再在Activity裡的onCreate方法裡調用setContentView(layoutId)設置即可

2、通過代碼動態管理

通過布局構造方法創建一種布局對象

把布局設置到Activity裡,相當於是把布局對象添加到Activity裡

再設置布局的相關屬性

根據業務需求設置View對象及位置

再把View對象add至布局中

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LinearLayout layout=new LinearLayout(this);
        super.setContentView(layout);
        layout.setOrientation(LinearLayout.VERTICAL);
        TextView show=new TextView(this);
        show.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        layout.addView(show);

    }
}

又如可以在Activity中動態添加和刪除控件

/*1 取到那個Layout*/
ViewGroup viewGroup = (ViewGroup)findViewById(R.id.layout);
/*2添加時,先創建對象,然後添加*/
ImageView newImageView = new ImageView(
              Animation2Activity.this);
newImageView.setImageResource(R.drawable.an);
viewGroup.addView(newImageView,
              new LayoutParams(
                  LayoutParams.FILL_PARENT,
                  LayoutParams.WRAP_CONTENT));
/*3 刪除時,直接刪除。*/
viewGroup.removeView(imageView);

3、xml和代碼混合布局

    
public class PicBrowserActivity extends Activity {
    private ImageView mImg;
    private int[] imgs=new int[]{
            R.mipmap.ic_blue_launcher,
            R.mipmap.ic_green_launcher,
            R.mipmap.ic_red_launcher,
            R.mipmap.pool_balls_05,
            R.mipmap.ic_toy,
            R.mipmap.ic_launcher
    };
    private int curIndex=0;//當前圖片的id
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        mImg= (ImageView) findViewById(R.id.id_show_img);
        final Handler handler=new Handler(){
            @Override
            public void handleMessage(Message msg) {
                if(msg.what==0x123){
                    mImg.setImageResource(imgs[curIndex++]);
                    if(curIndex>=5){
                        curIndex=5;
                    }
                }
            }
        };

        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                Message msg=new Message();
                msg.what=0x123;
                handler.sendMessage(msg);
            }
        },0,1000);
    }
}

4、HTML代碼構建

其實這一種嚴格來說應該不算是全新的方式,主要原理就是借助了WebView來實現javascript和java代碼的互相交互,所以我們還可以通過HTML/HTML5的方式來構建自己的UI。

首先,定義WebView,既然我們要借助WebView,肯定要先在xml布局文件中定義(當然也可以在代碼中去構建)

布局很簡單我就只定義了一個WebView

<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingleft="@dimen/activity_horizontal_margin" android:paddingright="@dimen/activity_horizontal_margin" android:paddingtop="@dimen/activity_vertical_margin" android:paddingbottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <webview android:id="@+id/id_table_webview" android:layout_width="match_parent" android:layout_height="match_parent">
</webview></relativelayout>
</code>
然後編寫我們的html文件(也可以在代碼中通過字符串的形式拼接成)
<!DOCTYPE html>
<head>
    <meta http-equiv="Content-Type" context="text/html;charset=UTF-8">
    <title>HTML UI FOR Andoid</title>
    <script type="text/javascript">
/**此方法是提供給java代碼調用的,和其他的js方法沒有什麼不同,就像我們在web開發下用js動態生成table一樣**/
function show(datas){
var jsonobjs=eval(datas);
var table=document.getElementById("table");
for(var i=0;i<jsonobjs.length;i++){
    var tr=table.insertRow(table.rows.length);
    var td=tr.insertCell(0);
    var td2=tr.insertCell(1);
    td2.align="right";
    var td3=tr.insertCell(2);
    td3.align="center";
    td.innerHTML=jsonobjs[i].id;
    td2.innerHTML=jsonobjs[i].name;
    td3.innerHTML=jsonobjs[i].phone;
}
}
</script>
</head>
<!--此employee為我們自己定義的js 對象,對應我們從Activity傳遞過來的js
自定義對象-->
<body onload="javascript:employee.showcontacts()">
<table border="1" width="100%" id="table" cellspacing="1">
    <tr>
        <td width="35%">姓名</td>
        <td width="30%">工號</td>
        <td width="35%">電話</td>
    </tr>
</table>
<a href="javascript:window.location.reload()">刷新</a>
</body>

單獨的HTML界面效果是這樣的
這裡寫圖片描述

再定義其他業務邏輯,比如說本例是獲取表格數據的,自然還需要去實現獲取數據的邏輯(JavaBean的Contacts實現就不貼出來了)
public class ContactsService {
    /**
     * 模擬獲取信息
     * @return
     */
    public List getContactsImf(){
        List contacts=new ArrayList();
        contacts.add(new Contacts(2009,"CrazyMO",9389281));
        contacts.add(new Contacts(2010,"Jim",5641021));
        contacts.add(new Contacts(2011,"Winds",897512));
        contacts.add(new Contacts(2012,"Jack",4524323));
        return contacts;
    }
}
最後我們的重頭戲就是在清單中申請訪問網絡的權限和實現在WebView中實現java和javascript代碼的交互,其實在這裡有很多細節都需要注意我都在代碼中一一注明,都是使用webView的相關知識點,這裡不便擴展,否則跑偏啦。
package com.crazymo.htmlui;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.WebSettings;
import android.webkit.WebView;

import com.crazymo.entity.Contacts;
import com.crazymo.service.ContactsService;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.List;

public class MainActivity extends Activity {
    private WebView mWebview;
    private ContactsService mContactsService;
    private final String url = "file:///android_asset/index.html";

    @SuppressLint("JavascriptInterface")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mWebview = (WebView) findViewById(R.id.id_table_webview);//獲取WebVIew
        mWebview.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);///一系列的初始化設置
        mWebview.getSettings().setAllowFileAccess(true);// 設置允許訪問文件數據
        mWebview.getSettings().setSupportZoom(true);//支持放大網頁功能
        mWebview.getSettings().setBuiltInZoomControls(true);//支持縮小網頁功能
        mWebview.getSettings().setJavaScriptEnabled(true);
        mWebview.addJavascriptInterface(new JSObject(), "employee");//前面對象,後面js中的調用名(我們可以看成這個JSObject類的實例是employee,用於給javascript裡調用
        mWebview.setWebViewClient(new MyWebViewCient());//設置打開i時不用系統浏覽器。使用本地WebView打開
        mWebview.loadUrl(url);
        mContactsService = new ContactsService();
    }

    private final class JSObject {
        /**
         * html中通過自定義的js 對象調用
         * 高能預警:If you've set your targetSdkVersion to 17 or higher, you must add the @JavascriptInterface
         即在一切需要在JS中調用的對象方法前加上@JavascriptInterface, 在api 17 即 Android 4.2.2 之後
         */
        @JavascriptInterface
        public void showcontacts() {

            List contactses = mContactsService.getContactsImf();
            JSONArray jsonArray = new JSONArray();
            try {
                for (Contacts contact : contactses) {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("id", contact.getId());
                    jsonObject.put("name", contact.getName());
                    jsonObject.put("phone", contact.getPhone());
                    jsonArray.put(jsonObject);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
            final String json = jsonArray.toString();
            /**
             *  A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread
             *  簡單來說就是html裡調用java方法和java調用js方法必須在同一線程
            */
            mWebview.post(new Runnable() {
                @Override
                public void run() {
                    mWebview.loadUrl("javascript:show('" + json + "')");//通過webview調用js 方法
                }
            });
        }
    }
}

這裡寫圖片描述

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved