Android Textview 一行居中 兩行居左

需求描述:

  1. 采用鴻洋大神打造的萬能的ListView GridView適配器
  2. ListView中的item中有一個TextView,該TextView的寬度確定,根據要顯示的內容長度動態調整文字的顯示方式:不超過1行居中顯示;超過1行的話無論第二行有幾個字,左對齊顯示。效果圖如下所示(這里只找到了居中的示例):
單行居中,兩行居左

剛開始寫的item布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fl_root"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <RoundedImageView
        android:id="@+id/iv_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@drawable/friendshipislandbg4"
        android:riv_border_width="0dp"
        android:riv_corner_radius="8dp" />
    <TextView
        android:id="@+id/tv_name"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_gravity="bottom"
        android:background="@drawable/bs_school_name_bg"
        android:gravity="center"
        android:maxLines="2"
        android:paddingLeft="20dp"
        android:paddingRight="20dp"
        android:textColor="#ffffff"
        android:textSize="16sp" />

</FrameLayout>

動態代碼調整TextView的Gravity代碼如下:

        @Override
        public void convert(ListviewViewHolder holder, TempDataBean item) {
            FrameLayout flRoot = (FrameLayout) holder.getView(R.id.fl_root);
            //動態調整GridView中每一個item的大小,防止圖片大小不同導致每一個item的大小不同
            ViewGroup.LayoutParams params = flRoot.getLayoutParams();
            params.height = displayWidth / 2 - MyUtils.dip2px(ctx, 18);
            params.width = displayWidth / 2 - MyUtils.dip2px(ctx, 18);
            flRoot.setLayoutParams(params);
            flRoot.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    startActivity(new Intent(BSItemActivity.this, BSDetailActivity.class));
                }
            });
            //顯示圖片
            mImageLoader.displayImage(item.getSchoolImage(), (ImageView) holder.getView(R.id.iv_school_image), options, mImageLoadingListener);
            //用來判斷是學校名字是一行或者兩行
            holder.setText(R.id.tv_name, item.getName());
            TextView tv = (TextView) holder.getView(R.id.tv_name);
            int lineCount = tv.getLineCount();
            if(lineCount<=1){
                //  1行居中
                tv.setGravity(Gravity.CENTER);
            }else{
                //  2行居左
                tv.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
            }

        }

編譯,安裝,跑起來,發現并不是預期的效果。現在的效果是第一次進入頁面,未滑動,無論是一行還是兩行都是居中顯示。將第一屏滑出界面,并再次滑入界面的時候,1行的居中,2行的居左(符合預期)。我擦,這是什么情況。帶著疑問,我將懷疑的目光轉向了大神造的輪子。

public static ListviewViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {
        if (convertView == null) {
            View itemView = LayoutInflater.from(context).inflate(layoutId, parent,false);
            ListviewViewHolder holder = new ListviewViewHolder(context, itemView, parent, position);
            holder.mLayoutId = layoutId;
            return holder;
        } else {
            ListviewViewHolder holder = (ListviewViewHolder) convertView.getTag();
            holder.mPosttion = position;
            return holder;
        }
}

我懷疑這段代碼是不是少了一些東西,大神沒有考慮到可能會有動態修改布局的操作,而僅僅在public void convert(ListviewViewHolder holder, TempDataBean item)方法中考慮了數據替換的操作。

我又懷疑是不是使用LayoutInflater填充出來的View和復用的convertView有一些不同。難道應該在使用LayoutInflater進行填充View的時候就進行動態修改布局的操作,對復用的convertView修改布局參數莫非晚了?說干就干,我就寫了一個抽象類,在使用LayoutInflater填充出View之后立即對View進行修改布局操作。抽象類如下:

public abstract class SetLayoutProperty {
    View itemView;
    int position;

    //獲得填充出來的View及對應的位置
    public void setItemView(View itemView, int position) {
        this.itemView = itemView;
        this.position = position;
    }
    
    //動態改變布局參數的具體操作
    public abstract void setLayoutProperty();

    public View getItemView() {
        return this.itemView;
    }

    public int getPosition() {
        return position;
    }
}

然后修改了大神造的ViewHolder如下:

public static ListviewViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position,SetLayoutProperty setLayoutProperty) {
        if (convertView == null) {
            View itemView = LayoutInflater.from(context).inflate(layoutId, parent,false);
            //主要增加了這個語句塊
            if (setLayoutProperty != null) {
                setLayoutProperty.setItemView(itemView,position);
                setLayoutProperty.setLayoutProperty();
            }
            ListviewViewHolder holder = new ListviewViewHolder(context, itemView, parent, position);
            holder.mLayoutId = layoutId;
            return holder;
        } else {
            ListviewViewHolder holder = (ListviewViewHolder) convertView.getTag();
            holder.mPosttion = position;
            return holder;
        }
}

由代碼可以看出,如果抽象類不為空,說明具體操作實現了這個抽象類,調用setLayoutProperty.setItemView(itemView,position)方法將需要的內容傳出,調用setLayoutProperty.setLayoutProperty()方法將執行具體的修改布局參數的邏輯。

又修改了大神造的Adapter如下:

/**
 * 在復用之前(展示之前)對一些布局參數進行調整
 *
 * @return
 */
public SetLayoutProperty setLayoutProperty() {
    return null;
}

使用輪子的時候我選擇這樣寫:

        @Override
        public SetLayoutProperty setLayoutProperty() {
            return new SetLayoutProperty() {
                @Override
                public void setLayoutProperty() {
                    //獲取條目布局
                    View itemView = this.getItemView();
                    TextView tv = (TextView) itemView.findViewById(R.id.tv_school_name);
                    tv.setText(datas.get(getPosition()).getSchoolName());
                    int lineCount = tv.getLineCount();
                    LogSwitchUtils.logD(BSItemActivity.class,"學校名字的內容為:"+datas.get(getPosition()).getSchoolName());
                    LogSwitchUtils.logD(BSItemActivity.class,"學校名字的行數為:"+lineCount);
                    if (lineCount <= 1) {
                        tv.setGravity(Gravity.CENTER);
                    } else {
                        tv.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
                    }
                }
            };
        }

        @Override
        public void convert(ListviewViewHolder holder, TempDataBean item) {...}

效果是:無論是否滑出或者滑入,無論是1行還是2行,都是居中顯示。
通過打印的日志,我發現通過getLineCount()方法獲得的數值都為0。不應該啊,讓我看看這個方法,于是就發現:

/**
 * Return the number of lines of text, or 0 if the internal Layout has not
 * been built.
 */
public int getLineCount() {
    return mLayout != null ? mLayout.getLineCount() : 0;
}

我了個去,此時此刻我只想知道如何讓 The internal Layout has been built.或者什么時候The internal Layout has been built.

于是乎,我就找度娘,我給度娘說:Return the number of lines of text, or 0 if the internal Layout has not been built.然后度娘沒有告訴我想要的答案:即如何讓?或者什么時候?

我又接著問度娘:“getlinecount一直是0?”

度娘說了:TextView可以通過getLineCount獲取行數,但是這里要在控件繪畫后才能獲取,否則調用這個函數返回值為0。但是我想在addText時就獲得text的行數,這樣我可以控制TextView的高度,請問有沒有一些開源的代碼或者想法可以實現在addText獲取行數呢?

哈哈哈哈....在知乎我知道了什么時候獲取行數不為0,代碼如下。

final TextView totalTitleNo = (TextView) findViewById(R.id.tv_ac_sub_account);
ViewTreeObserver vto = totalTitleNo.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
    @Override
    public boolean onPreDraw() {
        int lineCount = totalTitleNo.getLineCount();
        System.out.println(lineCount);
    }
});

迫不及待,我趕緊試試:

        @Override
        public void convert(ListviewViewHolder holder, TempDataBean item) {
            FrameLayout flRoot = (FrameLayout) holder.getView(R.id.root_fl);
            ViewGroup.LayoutParams params = flRoot.getLayoutParams();
            params.height = displayWidth / 2 - MyUtils.dip2px(ctx, 18);
            params.width = displayWidth / 2 - MyUtils.dip2px(ctx, 18);
            flRoot.setLayoutParams(params);
            flRoot.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    startActivity(new Intent(BSItemActivity.this, BSDetailActivity.class));
                }
            });
            //顯示圖片
            mImageLoader.displayImage(item.getSchoolImage(), (ImageView) holder.getView(R.id.iv_school_image), options, mImageLoadingListener);
            //為測試的控件設置值,用來判斷是學校名字是一行或者兩行
            holder.setText(R.id.tv_school_name, item.getSchoolName());
            final TextView tv = (TextView) holder.getView(R.id.tv_school_name);
            ViewTreeObserver vto = tv.getViewTreeObserver();
            //這個監聽器看名字也知道了,就是在繪畫完成之前調用的,在這里面可以獲取到行數,當然也可以獲取到寬高等信息。
            vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    int lineCount = tv.getLineCount();
                    LogSwitchUtils.logD(BSItemActivity.class, "學校名字的行數為:" + lineCount);
                    if (lineCount <= 1) {
                        tv.setGravity(Gravity.CENTER);
                        //tv.invalidate();
                    } else {
                        tv.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
                        //tv.invalidate();
                    }
                    return true;
                }
            });
        }

一開始,我的最后一句代碼是return false;但發現不行,該界面顯示不出來但一直打Log,于是就選擇返回了true。

一開始,最后一個注釋其實并不是注釋,但是當我將它注釋掉,發現結果依然是正確的,它就成了注釋。

在解決問題的時候,我還問過度娘:android Textview 一行居中,兩行居左?

檢索度娘得到了如下使用布局文件使TextView實現一行居中,兩行居左的效果:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/root_fl"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <com.makeramen.roundedimageview.RoundedImageView
        android:id="@+id/iv_school_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@drawable/friendshipislandbg4"
        app:riv_border_width="0dp"
        app:riv_corner_radius="8dp" />

    //該層使文字顯示在底部
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@drawable/bs_school_name_bg"
        android:layout_gravity="bottom">

        <LinearLayout
            //該層使單行居中
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:orientation="vertical">

            <TextView
                //該層使兩行居左
                android:paddingLeft="20dp"
                android:paddingRight="20dp"
                android:id="@+id/tv_school_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="left"
                android:maxLines="2"
                android:textColor="#ffffff"
                android:textSize="16sp" />
        </LinearLayout>
    </RelativeLayout>

</FrameLayout>

至此,實現【Android Textview 一行居中 兩行居左】需求時我的所想,所做,所得都記錄在了這里,便于以后復習。

結論

  1. 大神造的輪子沒有錯,是自己的理解有錯。但敢于向權威質疑的精神是對的,在修改輪子的時候,順便練習了使用抽象類和接口的使用;
  2. 實現TextView的單行居中,兩行居左方法有:動態調整布局參數;完善布局文件;
  3. 深刻體會了textview.getLineCount()方法。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容