一起擼個(gè)朋友圈吧(step5) - 控件篇【點(diǎn)擊展開】

項(xiàng)目地址:https://github.com/razerdp/FriendCircle
一起擼個(gè)朋友圈吧這是本文所處文集藕甩,所有更新都會(huì)在這個(gè)文集里面哦侍匙,歡迎關(guān)注

上篇鏈接:http://www.reibang.com/p/1f85d3978bb5
下篇鏈接:http://www.reibang.com/p/26dd3aad965a

終于進(jìn)入自定義控件篇了待侵,不知道有沒有人興奮呢颗胡,反正在下很興奮舶担。-V-


本篇將會(huì)實(shí)現(xiàn)一個(gè)比較簡單的控件:點(diǎn)擊展開全文
嗯惭婿。找田。歌憨。大概效果圖是這樣的:

效果圖

這個(gè)東東估計(jì)是整一個(gè)工程里最為簡單的一個(gè)控件了,當(dāng)然墩衙,網(wǎng)上也有很多例子务嫡,實(shí)現(xiàn)的都是類似的,本篇也都是一樣實(shí)現(xiàn)方法漆改。


在開始之前心铃,不妨來想想如何實(shí)現(xiàn)這個(gè)控件,就目前為止挫剑,在下想到了兩個(gè)方案:

  • 繼承TextView去扣,通過行數(shù)判斷是否有全文,如果有樊破,則在原文另起一行愉棱,通過SpannableStringBuilder拼接原文+\n+包含點(diǎn)擊事件的ClickableSpan,然后動(dòng)態(tài)改變maxLines
  • 通過繼承LinearLayout捶码,該layout包含2個(gè)textview羽氮,一個(gè)用來展示,一個(gè)用來點(diǎn)擊惫恼,通過行數(shù)判斷是否有全文档押,如果有,則點(diǎn)擊用的textview設(shè)為visible祈纯,否則設(shè)為gone令宿,點(diǎn)擊事件動(dòng)態(tài)改變展示用的textview的maxLines

經(jīng)過測試,第一個(gè)方法實(shí)現(xiàn)較難腕窥,主要是因?yàn)榱砥鹨恍械膯栴}粒没,因?yàn)樵瓉碚故镜臅r(shí)候已經(jīng)設(shè)置maxLines,如果要另起一行就意味著要增加maxLines簇爆,導(dǎo)致原文也展示了出來癞松,然后才是全文爽撒,因此不可取,遂采取方案2响蓉。


方案想完了硕勿,那么我們開工吧

按照我的習(xí)慣,肯定是先定義attrs枫甲,因?yàn)閺亩x屬性開始我可以大概設(shè)計(jì)一個(gè)雛形出來源武。

<declare-styleable name="ClickShowMoreLayout">
      <attr name="show_line" format="integer"/>
      <attr name="click_text" format="string"/>
      <attr name="text_color" format="color"/>
      <attr name="text_size" format="dimension"/>
  </declare-styleable>

我們定義四個(gè)屬性,分別為:最多展示行數(shù)想幻,點(diǎn)擊展開的textview文字粱栖,展示文字的顏色以及展示文字的大小。

然后就是構(gòu)造器里面一大堆東東脏毯,這里就不貼代碼闹究,弄張圖吧

構(gòu)造器初始化

initView方法里面執(zhí)行的是兩個(gè)textview的初始化:

 private void initView(Context context) {
        mTextView=new TextView(context);
        mClickToShow=new TextView(context);

        mTextView.setTextSize(textSize);
        mTextView.setTextColor(textColor);
        mTextView.setMaxLines(showLine);

        mClickToShow.setTextSize(textSize);
        mClickToShow.setTextColor(getResources().getColor(R.color.nick));
        mClickToShow.setText(clickText);

        LinearLayout.LayoutParams params= new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        params.topMargin= UIHelper.dipToPx(context,10f);
        mClickToShow.setLayoutParams(params);
        mClickToShow.setOnClickListener(this);

        setOrientation(VERTICAL);
        addView(mTextView);
        addView(mClickToShow);
    }

值得注意的是,我們的layoutparams不可以通過getLayoutParams拿到哦抄沮,那是個(gè)空的跋核。

重頭戲是設(shè)置文字的方法和onClick方法:

 public void setText(String str){
        mTextView.setText(str);
        mTextView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                if (!hasGetLineCount) {
                    hasMore = mTextView.getLineCount() > showLine;
                    hasGetLineCount=true;
                }
                mClickToShow.setVisibility(hasMore?VISIBLE:GONE);
                mTextView.getViewTreeObserver().removeOnPreDrawListener(this);
                return true;
            }
        });
    }

@Override
public void onClick(View v) {
        if (((TextView)v).getText().toString().equals(clickText)){
            mTextView.setMaxLines(Integer.MAX_VALUE);
            mClickToShow.setText("收起");
        }else {
            mTextView.setMaxLines(showLine);
            mClickToShow.setText(clickText);
        }
    }   
    

要判斷是否有更多內(nèi)容,我們只能獲取TextView繪制出來時(shí)文字的總行數(shù)叛买,那么文字都還沒繪制上去,我們應(yīng)該怎么拿到這個(gè)總行數(shù)呢蹋订,我們當(dāng)然不可以在onDraw里面拿率挣,于是我們就在onPreDraw里面拿,關(guān)于這里露戒,待會(huì)說說椒功。
拿到總行數(shù)后跟我們的最大顯示行數(shù)比較一下,然后得到是否有更多進(jìn)而設(shè)置點(diǎn)擊textview的可見性就完成了智什。

本篇完成动漾,下篇將會(huì)實(shí)現(xiàn)點(diǎn)贊展示的控件。


以下涉及官方源碼荠锭,稍微枯燥旱眯,可以跳過。

關(guān)于onPreDraw()证九,文檔是這么描述的:

Callback method to be invoked when the view tree is about to be drawn. At this point, all views in the tree have been measured and given a frame. Clients can use this to adjust their scroll bounds or even to request a new layout before drawing occurs.

(大概意思是【渣翻】:view樹在onDraw之前會(huì)回調(diào)這個(gè)方法删豺,此時(shí)view已經(jīng)進(jìn)行過measure【也就是可以拿到寬高】,在draw之前愧怜,我們可以進(jìn)行滑動(dòng)界限的調(diào)整【應(yīng)該是類似與ViewDragHelper那個(gè)邊界限定吧】甚至是重新部署)

而TextView關(guān)于文字的部署呀页,其實(shí)是與兩個(gè)layout有關(guān),一個(gè)是StaticLayout拥坛,一個(gè)是DynamicLayout這兩者的區(qū)別簡單來說就是setText時(shí)用的是普通的字符串還是包含有span的字符集合(另外還有BoringLayout 用于單行字符串的)蓬蝶〕痉郑【詳情請谷歌TextView渲染機(jī)制】

而既然textview實(shí)現(xiàn)了ViewTreeObserver.OnPreDrawListener這個(gè)接口,那么textview必定實(shí)現(xiàn)了這個(gè)方法回調(diào)丸氛,而且必定是有得到StaticLayout或者DynamicLayout培愁,否則我們得到的linecount只能為0.

于是我們打算找找是否實(shí)現(xiàn)了StaticLayout

我們可以查看TextView源碼:

onPreDraw

在assumeLayout我們又可以找到這個(gè)方法

makeNewLayout(width, physicalWidth, UNKNOWN_BORING, UNKNOWN_BORING,physicalWidth, false);

其他參數(shù)先不管,我們先找到目標(biāo)
在這個(gè)方法里面我們繼續(xù)可以找到這個(gè)方法

makeNewLayout

在這個(gè)方法里面雪位,我們終于找到了我們需要的東西了:

makeSingleLayout
makeSingleLayout

可以看到竭钝,如果有span使用的是dynamiclayout,如果是singleline雹洗,則用boringlayout香罐,如果都沒有(即result==null),則用的是staticlayout

我們不妨繼續(xù)看看build里面的方法:

 public StaticLayout build() {
            StaticLayout result = new StaticLayout(this);
            Builder.recycle(this);
            return result;
        }

而StaticLayout最終調(diào)用的是Layout的方法时肿,然而Layout的getLineCount是抽象方法庇茫,那么只能是StaticLayout實(shí)現(xiàn)這個(gè)方法了,經(jīng)過一直查找螃成,最終發(fā)現(xiàn)在out這個(gè)私有方法里面有關(guān)于mLineCount的計(jì)數(shù)

out

其實(shí)到這里旦签,我們可以大膽猜測控件或者其他什么元素的擺放是一行一行來放的,如果超過了寸宏,則另起一行直到放完為止宁炫。當(dāng)然,這僅僅是我的猜測氮凝,并沒有去查證羔巢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市罩阵,隨后出現(xiàn)的幾起案子竿秆,更是在濱河造成了極大的恐慌,老刑警劉巖稿壁,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幽钢,死亡現(xiàn)場離奇詭異,居然都是意外死亡傅是,警方通過查閱死者的電腦和手機(jī)匪燕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來落午,“玉大人谎懦,你說我怎么就攤上這事±U” “怎么了界拦?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長梗劫。 經(jīng)常有香客問我享甸,道長截碴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任蛉威,我火速辦了婚禮日丹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蚯嫌。我一直安慰自己哲虾,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布择示。 她就那樣靜靜地躺著束凑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪栅盲。 梳的紋絲不亂的頭發(fā)上汪诉,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機(jī)與錄音谈秫,去河邊找鬼扒寄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛拟烫,可吹牛的內(nèi)容都是我干的该编。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼硕淑,長吁一口氣:“原來是場噩夢啊……” “哼上渴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起喜颁,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎曹阔,沒想到半個(gè)月后半开,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赃份,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年寂拆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抓韩。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纠永,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出谒拴,到底是詐尸還是另有隱情尝江,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布英上,位于F島的核電站炭序,受9級特大地震影響啤覆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜惭聂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一窗声、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辜纲,春花似錦笨觅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至幽邓,卻和暖如春炮温,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背牵舵。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工柒啤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人畸颅。 一個(gè)月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓担巩,卻偏偏與公主長得像审磁,于是被迫代替她去往敵國和親薛耻。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容