UI--多行文本摺疊展開效果

1.概述

  經常在APP中能看到有引用文章或大段博文的內容,他們的展示樣式也有點兒意思,默認是摺疊的,當你點擊文章之後它會自動展開。再次點擊他又會縮回去。 
  網上有找到部分效果,感覺不是很滿意。最後自己嘗試用 自定義佈局layout 寫了個demo。比較簡陋,不過可以用了。有這方面需求的朋友可以稍加改造下。如有更好的創意,也不妨分享一下。 
   
效果圖: 
多行文本摺疊展開


2.具體實現

  但從實現效果方面來看,只用簡單定義必要view即可,後變爲了方便擴展使用和挪用,又對整個佈局進行封裝,方便直接使用。

2.1 通過多個佈局組合實現

  第一想法當然是用多個View組合來實現。那麼久定義一個LinearLayout佈局分別嵌套TextView和ImageView來做。 
  大概步驟: 
定義佈局,垂直的線性LinearLayout佈局、TextView和ImageView。 在layout中定義基本組件。 
設置TextView的高度爲指定行數*行高。 不使用maxLine的原因是maxLine會控制顯示文本的行數,不方便後邊使用動畫展開全部內容。因此這裏TextView的高度也因該爲wrap_content。 
給整個佈局添加點擊事件,綁定動畫。 點擊時,若TextView未展開則展開至其實際高度,imageView 旋轉;否則回縮至 指定行數*行高 , imageView 旋轉縮回。 
  

開始編寫代碼:

  1.在xml中定義佈局:

<code class="language-xml hljs  has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">LinearLayout
</span>        <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:id</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"@+id/description_layout"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_width</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"match_parent"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_height</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"wrap_content"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:orientation</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"vertical"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:paddingLeft</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"12dip"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:paddingRight</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"12dip"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:paddingTop</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"5dip"</span> ></span>

        <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">TextView
</span>            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:id</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"@+id/description_view"</span>
            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_width</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"match_parent"</span>
            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_height</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"wrap_content"</span>
            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:textColor</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"@android:color/black"</span>
            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:textSize</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"18dip"</span> ></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">TextView</span>></span>

        <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">ImageView
</span>            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:id</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"@+id/expand_view"</span>
            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_width</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"wrap_content"</span>
            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_height</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"wrap_content"</span>
            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:layout_gravity</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"right"</span>
            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:paddingBottom</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"5dip"</span>
            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:paddingLeft</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"5dip"</span>
            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:paddingRight</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"5dip"</span>
            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:paddingTop</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"5dip"</span>
            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:src</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"@drawable/text_ic_expand"</span>
            <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">android:visibility</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"gone"</span> /></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">LinearLayout</span>></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li></ul>

  2.首先在activity中定義並初始化這些view:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MainActivity</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Activity</span> {</span>
    TextView descriptionView;
    View layoutView ,expandView; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//LinearLayout佈局和ImageView</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> maxDescripLine = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//TextView默認最大展示行數</span>

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//在OnCreate中初始化</span>
    {
        layoutView = findViewById(R.id.description_layout);
        descriptionView = (TextView)findViewById(R.id.description_view);
        expandView = findViewById(R.id.expand_view);
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>

  3.然後設置textview顯示文本,再根據默認展示行數設置其高度,並根據其是否已完全顯示(當前展示行數是否大於等於實際行數)來判斷需不需要點擊更多按鈕。

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//設置文本</span>
    descriptionView.setText(getText(R.string.content));

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//descriptionView設置默認顯示高度</span>
    descriptionView.setHeight(descriptionView.getLineHeight() * maxDescripLine);
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//根據高度來判斷是否需要再點擊展開</span>
    descriptionView.post(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Runnable() {

            <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() {
                expandView.setVisibility(descriptionView.getLineCount() > maxDescripLine ? View.VISIBLE : View.GONE);
            }
        }); </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

  因爲textView設置的是wrap_content,所以會顯示實際高度和行數,這裏根據maxDescripLine來設置其高度。 
  看了最後一行代碼可能有人會問?ImageView (點擊展開更多)是否應該顯示 的判斷邏輯爲什麼要放在post方法裏邊呢? 這是由於在OnCreate方法中定義設置的textView不會馬上渲染並顯示,所以textview的getLineCount()獲取到的值一般都爲零,因此使用post會在其繪製完成後來對ImageView進行顯示控制。 
  ps: 感覺我描述不清的朋友可以看下stackoverflow 上的講解 how to use getlinecount() in textview android.

  4.給layoutView設置點擊事件。 
  給ImageView定義一個RotateAnimation的旋轉動畫,在旋轉過程中根據旋轉百分比進度控制textView高度,進而達到我們想要的效果。

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">    layoutView.setOnClickListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> View.OnClickListener() {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> isExpand;<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//是否已展開的狀態</span>

            <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onClick</span>(View v) {
                isExpand = !isExpand;
                descriptionView.clearAnimation();<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//清楚動畫效果</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> deltaValue;<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//默認高度,即前邊由maxLine確定的高度</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> startValue = descriptionView.getHeight();<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//起始高度</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> durationMillis = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">350</span>;<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//動畫持續時間</span>
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (isExpand) {
                    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
                    * 摺疊動畫
                    * 從實際高度縮回起始高度
                    */</span>
                    deltaValue = descriptionView.getLineHeight() * descriptionView.getLineCount() - startValue;
                    RotateAnimation animation = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> RotateAnimation(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">180</span>, Animation.RELATIVE_TO_SELF, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>f, Animation.RELATIVE_TO_SELF, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>f);
                    animation.setDuration(durationMillis);
                    animation.setFillAfter(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>);
                    expandView.startAnimation(animation);
                } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
                    <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
                    * 展開動畫
                    * 從起始高度增長至實際高度
                    */</span>
                    deltaValue = descriptionView.getLineHeight() * maxDescripLine - startValue;
                    RotateAnimation animation = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> RotateAnimation(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">180</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, Animation.RELATIVE_TO_SELF, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>f, Animation.RELATIVE_TO_SELF, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>f);
                    animation.setDuration(durationMillis);
                    animation.setFillAfter(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>);
                    expandView.startAnimation(animation);
                }
                Animation animation = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Animation() {
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">applyTransformation</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> interpolatedTime, Transformation t) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//根據ImageView旋轉動畫的百分比來顯示textview高度,達到動畫效果</span>
                        descriptionView.setHeight((<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>) (startValue + deltaValue * interpolatedTime));
                    }
                };
                animation.setDuration(durationMillis);
                descriptionView.startAnimation(animation);
            }
        });</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li></ul>

  至此,通過佈局已經實現了我們想要的效果。具體代碼參見代碼示例 的第一部分。 
  當然,我們可以這樣使用,但是每次都這麼重寫未免顯得有些麻煩。因此有必要把他寫成一個單獨控件,方便我們以後的開袋即食。廢話不多說,上菜。

2.2 通過自定義View組合封裝

  這個view的佈局結構並不打算使用xml來定義layout,直接定義一個繼承LinearLayout的MoreTextView類.這個類裏邊添加TextView和ImageView。

1.使用styleable自定義View屬性

  爲了後邊能夠方便的在xml佈局中使用MoreTextView這個自定義View,類似通過

android:text = “XXX” 
android:textSize = “XXX”

這樣快捷的綁定文本內容和設置字體大小等屬性,我們可以通過 declare-styleable在values文件下的xml中自定義我們想要的屬性,並在View中獲取和使用。詳細使用declare-styleable的內容會在後邊補充,這裏簡要說下。 
  比如,MoreTextView應該有的基本屬性,像 文本字體大小(textSize)、顏色(textColor)和文本內容(text),還有默認顯示行數(maxLine)等幾種屬性。我們要想像TextView一樣直接在xml中設置綁定,可以這樣做。 
  首先在values目錄下新建個attrs.xml(名字隨意),並定義MoreTextView這些屬性。

<code class="language-xml hljs  has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-pi" style="color: rgb(0, 102, 102); box-sizing: border-box;"><?xml version="1.0" encoding="utf-8"?></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">resources</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">declare-styleable</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">name</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"MoreTextStyle"</span>></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">attr</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">name</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"textSize"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">format</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"dimension"</span>/></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">attr</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">name</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"textColor"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">format</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"color"</span>/></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">attr</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">name</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"maxLine"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">format</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"integer"</span> /></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">attr</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">name</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"text"</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">format</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"string"</span> /></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">declare-styleable</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">resources</span>></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

2.自定義MoreTextView並獲取這些屬性的值

  上邊定義了這些屬性,就等於允許我們在xml中使用

more:text = “XXX” 
more:textSize = “XXX” 
more : textColor = “XXX” 
more : maxLine = “XXX” 
            (注: more這個關鍵字可以隨意)

這樣直接設置屬性值。那麼具體怎麼取值,我們稍後來講。 
  (1)定義MoreTextView的屬性:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MoreTextView</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">LinearLayout</span>{</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> TextView contentView; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//文本正文</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> ImageView expandView; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//展開按鈕</span>

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//對應styleable中的屬性</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> textColor; 
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> textSize;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> maxLine;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> String text;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//默認屬性值</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> defaultTextColor = Color.BLACK;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> defaultTextSize = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">12</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> defaultLine = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//....實現部分略</span>
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul>

  (2)MoreTextView的構造方法:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">MoreTextView</span>(Context context, AttributeSet attrs) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>(context, attrs);
        initalize(); 
        initWithAttrs(context, attrs); 
        bindListener();
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

這三個方法簡單說明下:

  • initalize()  初始化並添加View。初始化TextView和ImageView,並添加到MoretextView中去。
  • initWithAttrs(context, attrs)  取值並設置。利用attrs從xml佈局中取我們配置好的text/textSize/textColor/maxLine等屬性的屬性值,並設置到View上去。
  • bindListener()  綁定點擊事件並設置動畫。 給當前MoreTextView設置點擊事件,實現點擊摺疊和展開。

各個方法的具體實現:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//初始化並添加View</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">initalize</span>() {
        setOrientation(VERTICAL); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//設置垂直佈局</span>
        setGravity(Gravity.RIGHT); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//右對齊</span>
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//初始化textView並添加</span>
        contentView = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TextView(getContext());
        addView(contentView, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//初始化ImageView並添加</span>
        expandView = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ImageView(getContext());
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> padding = dip2px(getContext(), <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>);
        expandView.setPadding(padding, padding, padding, padding);
        expandView.setImageResource(R.drawable.text_ic_expand);
        LinearLayout.LayoutParams llp = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        addView(expandView, llp);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>

  取值並設置這部分有必要將一下。我們利用TypedArray從定義的styleable中取出屬性值,賦給我們定義好的類的屬性變量。記得取完之後調用recycle()回收釋放。

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">initWithAttrs</span>(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs,  
                R.styleable.MoreTextStyle);  
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> textColor = a.getColor(R.styleable.MoreTextStyle_textColor,  
                defaultTextColor);  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//取顏色值,默認defaultTextColor</span>
        textSize = a.getDimensionPixelSize(R.styleable.MoreTextStyle_textSize, defaultTextSize);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//取顏字體大小,默認defaultTextSize</span>
        maxLine = a.getInt(R.styleable.MoreTextStyle_maxLine, defaultLine);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//取顏顯示行數,默認defaultLine</span>
        text = a.getString(R.styleable.MoreTextStyle_text);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//取文本內容</span>

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//綁定到textView   bindTextView(textColor,textSize,maxLine,text);</span>

        a.recycle();<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//回收釋放</span>
    }

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//綁定到textView   </span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">bindTextView</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> color,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> size,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> line,String text){
        contentView.setTextColor(color);
        contentView.setTextSize(TypedValue.COMPLEX_UNIT_PX,size);
        contentView.setText(text);
        contentView.setHeight(contentView.getLineHeight() * line);
        post(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Runnable() {<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//前面已講,不再贅述</span>

            <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() {
                expandView.setVisibility(contentView.getLineCount() > line ? View.VISIBLE : View.GONE);

            }
        });
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li></ul>

最後設置點擊事件。

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//點擊展開與摺疊,不再贅述</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">bindListener</span>(){
        setOnClickListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> View.OnClickListener() {
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> isExpand;

            <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onClick</span>(View v) {
                isExpand = !isExpand;
                contentView.clearAnimation();
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> deltaValue;
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> startValue = contentView.getHeight();
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> durationMillis = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">350</span>;
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (isExpand) {
                    deltaValue = contentView.getLineHeight() * contentView.getLineCount() - startValue;
                    RotateAnimation animation = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> RotateAnimation(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">180</span>, Animation.RELATIVE_TO_SELF, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>f, Animation.RELATIVE_TO_SELF, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>f);
                    animation.setDuration(durationMillis);
                    animation.setFillAfter(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>);
                    expandView.startAnimation(animation);
                } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {
                    deltaValue = contentView.getLineHeight() * maxLine - startValue;
                    RotateAnimation animation = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> RotateAnimation(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">180</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, Animation.RELATIVE_TO_SELF, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>f, Animation.RELATIVE_TO_SELF, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>f);
                    animation.setDuration(durationMillis);
                    animation.setFillAfter(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>);
                    expandView.startAnimation(animation);
                }
                Animation animation = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Animation() {
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">applyTransformation</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> interpolatedTime, Transformation t) {
                        contentView.setHeight((<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>) (startValue + deltaValue * interpolatedTime));
                    }

                };
                animation.setDuration(durationMillis);
                contentView.startAnimation(animation);
            }
        });
    }
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li></ul>

另外,定義幾個方法方便外部調用(獲取文本TextView,直接設置文本內容),同時還定義了一個dip轉像素的靜態方法。

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> TextView <span class="hljs-title" style="box-sizing: border-box;">getTextView</span>(){
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> contentView;
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">setText</span>(CharSequence charSequence){
        contentView.setText(charSequence);
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> <span class="hljs-title" style="box-sizing: border-box;">dip2px</span>(Context context, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> dipValue){              
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> scale = context.getResources().getDisplayMetrics().density;                   
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>)(dipValue * scale + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>f);           
    }      </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>

  其實到這裏,我們的自定義多文本摺疊展開MoreTextView已經完成了。如何使用呢?

  • 在layout/xx.xml中使用 
    要想方便的使用我們剛剛的自定義屬性來定義值,記得在xml namespace中定義應用:

    自動引用命名空間res-auto 
    xmlns:more=”http://schemas.android.com/apk/res-auto” 
    或者 直接定義包名 
    xmlns:more=”http://schemas.android.com/apk/res/com.qiao.moretext”

    命名空間後邊跟的 more即下邊你要使用自定義屬性的開頭部分。 
    比如我們的activity_main.xml

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><LinearLayout xmlns:android=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"http://schemas.android.com/apk/res/android"</span>
xmlns:more=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"http://schemas.android.com/apk/res/com.qiao.moretext"</span>
    android:id=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"@+id/root"</span>
    android:layout_width=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"match_parent"</span>
    android:layout_height=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"match_parent"</span>
    android:background=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"@android:color/white"</span>
    android:orientation=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"vertical"</span> >

     <com.qiao.moretext.MoreTextView
        android:layout_width=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"match_parent"</span>
        android:layout_height=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"wrap_content"</span>
        android:layout_margin=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"5dip"</span> 
        more:textColor=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"@android:color/black"</span>
        more:textSize=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"18dip"</span>
        more:maxLine=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"3"</span>
        more:text=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"@string/content"</span>/>

</LinearLayout></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>
  • 在java中直接定義使用 
    由於上邊定義MoreTextView只定義了一種構造方法 MoreTextView(Context context, AttributeSet attrs) ,所以使用時,也只能:
<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">    MoreTextView content = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> MoreTextView(MainActivity.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>);
    content.setText(getText(R.string.content));
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//然後addview到你要添加的地方</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

  當然,聰明如你,可肯定知道怎麼定義另外的構造方法來簡單實用啦。 
  –> 
  MoreTextView(Context context){ 
    //使用默認值直接初始化 
    bindTextView(); 
  }


3.綜述

  綜上呢,我們已經完成了所要實現的功能,作爲UI呢,他可能會有些簡陋,但作爲一個demo起到示範作用已經夠了。後邊我們可能會考慮把它作爲微博的一個listitem做成列表一樣,並加入點贊等功能。有興趣不妨做一下咯。。 
  源碼示例下載地址

轉載請保留出處 by Qiao 
http://blog.csdn.net/qiaoidea/article/details/45568653

發佈了27 篇原創文章 · 獲贊 111 · 訪問量 58萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章