欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android 動(dòng)態(tài)改變布局實(shí)例詳解

 更新時(shí)間:2016年11月15日 10:07:48   作者:AngelDevil  
這篇文章主要介紹了Android 動(dòng)態(tài)改變布局實(shí)例詳解的相關(guān)資料,這里舉例說(shuō)明如何實(shí)現(xiàn)動(dòng)態(tài)改變布局的例子,幫助大家學(xué)習(xí)理解,需要的朋友可以參考下

Android 動(dòng)態(tài)改變布局

               最近項(xiàng)目需求,動(dòng)態(tài)的改變布局,為了增加客戶體驗(yàn),尤其是在輸入框出現(xiàn)小鍵盤的時(shí)候,為了避免小鍵盤遮擋APP內(nèi)容就需要?jiǎng)討B(tài)改變布局:

                先看下實(shí)現(xiàn)效果圖:

其實(shí)是一個(gè)軟件的登錄界面,初始是第一個(gè)圖的樣子,當(dāng)軟鍵盤彈出后變?yōu)榈诙€(gè)圖的樣子,因?yàn)榈卿浗缑嬗杏脩裘?、密碼、登錄按鈕,不這樣的話軟鍵盤彈出后會(huì)遮住登錄按鈕(其實(shí)之前的實(shí)現(xiàn)放到了ScrollView里面,監(jiān)聽(tīng)軟鍵盤彈出后滾動(dòng)到底部,軟鍵盤隱藏后滾動(dòng)到頂部,也是可以的)。

最簡(jiǎn)單的方法就是多加幾個(gè)冗余的View,根據(jù)軟鍵盤的狀態(tài)隱藏不需要的View,顯示需要的View,但這樣感覺(jué)太挫了,然后就想起了前兩年研究的RelativeLayout布局,RelativeLayout中子控件的布局都是相對(duì)位置,只需要在軟鍵盤彈出隱藏時(shí)改變應(yīng)用的位置規(guī)則就行了。

先來(lái)看一下布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/root"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:padding="20dp"
  tools:context="${packageName}.${activityClass}" >

  <RelativeLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true" >

    <ImageView
      android:id="@+id/logo"
      android:layout_width="150dp"
      android:layout_height="150dp"
      android:layout_centerHorizontal="true"
      android:scaleType="centerCrop"
      android:src="@drawable/ic_launcher"
      tools:ignore="ContentDescription" />

    <TextView
      android:id="@+id/label"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_below="@id/logo"
      android:layout_centerHorizontal="true"
      android:layout_marginLeft="10dp"
      android:layout_marginTop="10dp"
      android:text="@string/hello_world"
      android:textSize="20sp" />
  </RelativeLayout>

  <EditText
    android:id="@+id/input"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/container"
    android:layout_margin="16dp"
    android:hint="Input sth."
    tools:ignore="HardcodedText" />

</RelativeLayout>

軟鍵盤的彈出隱藏用OnGlobalLayoutListener監(jiān)聽(tīng)實(shí)現(xiàn),對(duì)Activity應(yīng)用android:windowSoftInputMode="stateHidden|adjustResize",這樣開始時(shí)軟鍵盤不顯示,當(dāng)軟鍵盤彈出時(shí)布局被Resize。

接下來(lái)是代碼,所有的代碼都在這里了

public class MainActivity extends Activity {

  private View root; // 最外層布局
  private View logo; // Logo圖標(biāo)
  private View label; // Logo附近的文字

  private int rootBottom = Integer.MIN_VALUE;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    root = findViewById(R.id.root);
    logo = findViewById(R.id.logo);
    label = findViewById(R.id.label);
    root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

      @Override
      public void onGlobalLayout() {
        Rect r = new Rect();
        root.getGlobalVisibleRect(r);
        // 進(jìn)入Activity時(shí)會(huì)布局,第一次調(diào)用onGlobalLayout,先記錄開始軟鍵盤沒(méi)有彈出時(shí)底部的位置
        if (rootBottom == Integer.MIN_VALUE) {
          rootBottom = r.bottom;
          return;
        }
        // adjustResize,軟鍵盤彈出后高度會(huì)變小
        if (r.bottom < rootBottom) {
          RelativeLayout.LayoutParams lp = (LayoutParams) logo.getLayoutParams();
          // 如果Logo不是水平居中,說(shuō)明是因?yàn)榻酉聛?lái)的改變Logo大小位置導(dǎo)致的再次布局,忽略掉,否則無(wú)限循環(huán)
          if (lp.getRules()[RelativeLayout.CENTER_HORIZONTAL] != 0) {
            // Logo顯示到左上角
            lp.addRule(RelativeLayout.CENTER_HORIZONTAL, 0); // 取消水平居中
            lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT); // 左對(duì)齊

            // 縮小Logo為1/2
            int height = logo.getHeight(); // getMeasuredHeight()
            int width = logo.getWidth();
            lp.width = width / 2;
            lp.height = height / 2;
            logo.setLayoutParams(lp);

            // Logo下的文字
            RelativeLayout.LayoutParams labelParams = (LayoutParams) label.getLayoutParams();
            labelParams.addRule(RelativeLayout.CENTER_HORIZONTAL, 0); // 取消水平居中
            labelParams.addRule(RelativeLayout.BELOW, 0); // 取消顯示到logo的下方
            labelParams.addRule(RelativeLayout.RIGHT_OF, R.id.logo); // 顯示到Logo的右方
            labelParams.addRule(RelativeLayout.CENTER_VERTICAL); // 垂直居中
            label.setLayoutParams(labelParams);
          }
        } else { // 軟鍵盤收起或初始化時(shí)
          RelativeLayout.LayoutParams lp = (LayoutParams) logo.getLayoutParams();
          // 如果沒(méi)有水平居中,說(shuō)明是軟鍵盤收起,否則是開始時(shí)的初始化或者因?yàn)榇颂巌f條件里的語(yǔ)句修改控件導(dǎo)致的再次布局,忽略掉,否則無(wú)限循環(huán)
          if (lp.getRules()[RelativeLayout.CENTER_HORIZONTAL] == 0) {
            // 居中Logo
            lp.addRule(RelativeLayout.CENTER_HORIZONTAL);
            lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);

            // 還原Logo為原來(lái)大小
            int height = logo.getHeight();
            int width = logo.getWidth();
            lp.width = width * 2;
            lp.height = height * 2;
            logo.setLayoutParams(lp);

            // Logo下的文字
            RelativeLayout.LayoutParams labelParams = (LayoutParams) label.getLayoutParams();
            labelParams.addRule(RelativeLayout.CENTER_HORIZONTAL); // 設(shè)置水平居中
            labelParams.addRule(RelativeLayout.BELOW, R.id.logo); // 設(shè)置顯示到Logo下面
            labelParams.addRule(RelativeLayout.RIGHT_OF, 0); // 取消顯示到Logo右面
            labelParams.addRule(RelativeLayout.CENTER_VERTICAL, 0); // 取消垂直居中
            label.setLayoutParams(labelParams);
          }
        }
      }
    });
  }
}

當(dāng)Activity啟動(dòng)時(shí)也會(huì)進(jìn)行Layout,此時(shí)用rootBottom記錄了初始時(shí)最外層布局底部的位置,此后當(dāng)軟鍵盤彈出時(shí),布局被壓縮,再次獲取同一個(gè)View底部的位置,如果比rootBottom小說(shuō)明軟鍵盤彈出了,如果大于或等于rootBottom說(shuō)明軟鍵盤隱藏了。

所有的代碼都在上面,也有詳細(xì)注釋,有兩點(diǎn)需要注意一下:

1.Activity啟動(dòng)時(shí)會(huì)進(jìn)行Layout,此時(shí)會(huì)調(diào)用onGlobalLayout,而且一般會(huì)調(diào)用兩次,這樣第二次時(shí)會(huì)進(jìn)入else語(yǔ)句,要注意過(guò)濾

2.軟鍵盤彈出或隱藏時(shí)進(jìn)入onGlobalLayout,此時(shí)根據(jù)需要縮放Logo的大小,并改變Logo和Label的位置,這些操作會(huì)引起再次onGlobalLayout,需要將之后的onGlobalLayout過(guò)濾掉,不然就無(wú)限循環(huán)了。

可以看到上面代碼中的過(guò)濾條件,以else語(yǔ)句中的為例,Activity啟動(dòng)時(shí)會(huì)進(jìn)入else,此時(shí)Logo是水平居中狀態(tài),會(huì)跳過(guò)else里面的if語(yǔ)句,這樣就處理掉了第一種情況。

當(dāng)因?yàn)檐涙I盤收起進(jìn)入else時(shí),Logo已經(jīng)因?yàn)閕f語(yǔ)句塊變?yōu)榱孙@示在左上角,所以會(huì)進(jìn)入else中的if語(yǔ)句,重新改變Logo為水平居中,由于修改了Logo的大小和位置,會(huì)導(dǎo)致再次進(jìn)入onGlobalLayout,仍是進(jìn)入else,但此時(shí)已經(jīng)設(shè)置Logo為水平居中了,不會(huì)再次進(jìn)入else中的if語(yǔ)句,這樣通過(guò)一個(gè)條件判斷就處理了上面提到的兩點(diǎn)注意事項(xiàng)。

關(guān)于addRule

RelativeLayout中每一個(gè)子控件所應(yīng)用的規(guī)則都是通過(guò)數(shù)組保存的,如下所示:



public static final int TRUE = -1;

public void addRule(int verb) {
  mRules[verb] = TRUE;
  mInitialRules[verb] = TRUE;
  mRulesChanged = true;
}

public void addRule(int verb, int anchor) {
  mRules[verb] = anchor;
  mInitialRules[verb] = anchor;
  mRulesChanged = true;
}

以某一規(guī)則的索引為下標(biāo),值就是規(guī)則對(duì)應(yīng)的anchor,如果是相對(duì)于另一個(gè)子控件,值就是另一個(gè)子控件的ID,如果是相對(duì)于父控件,值就是`TRUE`,即-1,如果沒(méi)有應(yīng)用某一規(guī)則值就是0,可以看到,removeRule就是把相應(yīng)位置的值改為了0:

public void removeRule(int verb) {
  mRules[verb] = 0;
  mInitialRules[verb] = 0;
  mRulesChanged = true;
 }

removeRule是API 17才加的方法,為了在API 17前也能使用,可以使用它的等價(jià)方法,像上面的例子中的一樣,使用addRule(verb, 0)。

感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

相關(guān)文章

最新評(píng)論