国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > Android > 正文

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

2019-12-12 04:39:32
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

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

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

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

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

最簡(jiǎn)單的方法就是多加幾個(gè)冗余的View,根據(jù)軟鍵盤(pán)的狀態(tài)隱藏不需要的View,顯示需要的View,但這樣感覺(jué)太挫了,然后就想起了前兩年研究的RelativeLayout布局,RelativeLayout中子控件的布局都是相對(duì)位置,只需要在軟鍵盤(pán)彈出隱藏時(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>

軟鍵盤(pán)的彈出隱藏用OnGlobalLayoutListener監(jiān)聽(tīng)實(shí)現(xiàn),對(duì)Activity應(yīng)用android:windowSoftInputMode="stateHidden|adjustResize",這樣開(kāi)始時(shí)軟鍵盤(pán)不顯示,當(dāng)軟鍵盤(pán)彈出時(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,先記錄開(kāi)始軟鍵盤(pán)沒(méi)有彈出時(shí)底部的位置        if (rootBottom == Integer.MIN_VALUE) {          rootBottom = r.bottom;          return;        }        // adjustResize,軟鍵盤(pán)彈出后高度會(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 { // 軟鍵盤(pán)收起或初始化時(shí)          RelativeLayout.LayoutParams lp = (LayoutParams) logo.getLayoutParams();          // 如果沒(méi)有水平居中,說(shuō)明是軟鍵盤(pán)收起,否則是開(kāi)始時(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)軟鍵盤(pán)彈出時(shí),布局被壓縮,再次獲取同一個(gè)View底部的位置,如果比rootBottom小說(shuō)明軟鍵盤(pán)彈出了,如果大于或等于rootBottom說(shuō)明軟鍵盤(pán)隱藏了。

所有的代碼都在上面,也有詳細(xì)注釋?zhuān)袃牲c(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.軟鍵盤(pán)彈出或隱藏時(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盤(pán)收起進(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ì)本站的支持!

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 惠安县| 台东市| 桃园市| 育儿| 张家川| 扬州市| 阿尔山市| 岳阳市| 库伦旗| 和林格尔县| 新津县| 尼木县| 平顺县| 渑池县| 汉沽区| 山东| 台东县| 壤塘县| 永寿县| 基隆市| 东源县| 乐平市| 盘锦市| 陇南市| 余干县| 太白县| 永安市| 聂拉木县| 惠东县| 济阳县| 海城市| 清丰县| 连云港市| 寻甸| 泗水县| 黄梅县| 大邑县| 德阳市| 南靖县| 平塘县| 惠来县|