完成了自訂ListView控制項使其內具備HeaderViewFooterView功能,則此自訂之ListView往後便可在多個類似的介面來使用,而且HeaderviewFooterView可以使用更複雜的View來實現特殊功能。
接下來,為使結果可顯現資料故須為ListView添加資料,在此範例中於MainActivity中添加一個自訂方法initSite()用於構造測試資料,其代碼如下: 
package com.wenbin.test;

import com.wenbin.test.site.Blog;
import com.wenbin.test.site.SinaSite;
import com.wenbin.test.site.Site;
import com.wenbin.test.site.User;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TextView;

public class MainActivity extends Activity implements OnItemClickListener {
private TextView usernameTextview;
private Site site;
@Override
public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);
      
       initSite();    //構造測試資料
                    usernameTextview=(TextView)findViewById(R.id.TextViewUsername);
       BlogListView sinaListView=(BlogListView)findViewById(R.id.sinaList);
       sinaListView.setOnItemClickListener(this);
       sinaListView.init(site);     //Site資料傳入作初始化
      
       findViewById(R.id.BtnWrite).setOnClickListener(new OnClickListener() {
              @Override
              public void onClick(View v) {
                    //TODO:
              }
       });
      
       findViewById(R.id.BtnRefresh).setOnClickListener(new OnClickListener() {
              @Override
              public void onClick(View v) {
                    //TODO:
              }
       });
      
       updateUserNameTextView();              //自訂方法
}

private void updateUserNameTextView() {
       usernameTextview.setText(R.string.unAuthUser);
}
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
       //TODO:
}
private void initSite(){           //自訂初始化Site方法
       site=new SinaSite();

       Blog blog=new Blog(site);
       blog.setPic("http://ww3.sinaimg.cn/thumbnail/6b8527b3jw6dbydoikpzuj.jpg");
       User user=new User();
       user.setVerified(true);
       blog.setUser(user);
       site.addBlog(blog);
      
       blog=new Blog(site);
       user=new User();
       user.setVerified(true);
       blog.setUser(user);
       Blog retBlog=new Blog();
       user=new User();
       user.setProfileImageUrl("");
       user.setScreenName("reply");
       retBlog.setUser(user);
       retBlog.setText("[爱你]求喜欢");
       retBlog.setPic("http://tp4.sinaimg.cn/1658122963/50/1282754213");
       blog.setRetweetedBlog(retBlog);
       site.addBlog(blog);
      
       for(int i=0;i<5;i++){
              try {
                    Thread.sleep(200);
              } catch (InterruptedException e) {
                    e.printStackTrace();
              }
              user=new User();
              blog=new Blog(site);
              blog.setUser(user);
              site.addBlog(blog);
       }
}
}
然後,為每個item列表項設計佈局檔blogview.xml,其內容如下所示(佈局規劃之思路:考量在特定位置須採用何種合乎需求之View元件,再設定其相關屬性,且考慮其它View元件之安排相對於此View元件之位置為何) 
n   blogview.xml檔內容:
<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout  
  xmlns:android="http://schemas.android.com/apk/res/android"  
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"  
  android:orientation="vertical"  
  android:padding="10dp" android:descendantFocusability="blocksDescendants"  
  android:background="@color/white">  
  <RelativeLayout android:layout_width="fill_parent"   
    android:layout_height="fill_parent" >  
    <WebView android:id="@+id/profileImage"  
        android:layout_width="48dp"  
        android:layout_height="48dp"  
        android:scrollbars="none"  
        android:layout_alignParentLeft="true"  
        android:background="@drawable/portrait">  
    </WebView>  
    <ImageView android:id="@+id/vImage"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_alignRight="@+id/profileImage"  
        android:layout_alignBottom="@+id/profileImage"  
        android:src="@drawable/v">  
    </ImageView>  
    <RelativeLayout android:layout_alignParentRight="true"  
        android:layout_toRightOf="@+id/profileImage"  
        android:layout_width="fill_parent"  
        android:layout_height="fill_parent"  
        android:layout_marginLeft="10dp">  
        <TextView android:id="@+id/userName" android:layout_height="wrap_content" android:layout_alignParentTop="true"  
            android:textColor="@color/red"  
            android:textSize="15sp"  
            android:paddingBottom="5dp" android:layout_width="fill_parent">  
        </TextView>  
        <TextView android:id="@+id/blogText" android:layout_height="wrap_content"  
            android:layout_below="@+id/userName"  
            android:textColor="@color/black"  
            android:textSize="15sp" android:layout_width="wrap_content">  
        </TextView>  
        <WebView android:id="@+id/smallImage"  
            android:layout_width="68dp"  
            android:layout_height="48dp"  
            android:scrollbars="none"  
            android:layout_below="@+id/blogText"  
            android:background="@drawable/image">  
        </WebView>      
        <RelativeLayout android:layout_width="fill_parent"   
            android:layout_height="wrap_content"  
            android:layout_below="@+id/smallImage"  
            android:background="@drawable/popup"  
            android:paddingTop="10dp"  
            android:paddingBottom="5dp"  
            android:paddingLeft="5dp"  
            android:paddingRight="5dp"  
            android:id="@+id/reBlog">  
            <TextView android:id="@+id/reBlogText" android:layout_width="fill_parent"  
                android:layout_height="wrap_content"  
                android:layout_below="@+id/reUserName"  
                android:textColor="@color/black"  
                android:textSize="15sp">  
            </TextView>     
            <WebView android:id="@+id/reImage"  
                android:layout_width="68dp"  
                android:layout_height="48dp"  
                android:scrollbars="none"  
                android:layout_below="@+id/reBlogText"  
                android:background="@drawable/image">  
            </WebView>          
        </RelativeLayout>   
        <TextView android:id="@+id/sourceText" android:layout_width="fill_parent"  
            android:layout_height="wrap_content"   
            android:layout_alignLeft="@+id/userName"  
            android:layout_below="@+id/reBlog"  
            android:textColor="@color/blue"  
            android:textSize="10sp"  
            android:paddingBottom="5dp">  
        </TextView>     
    </RelativeLayout>  
  </RelativeLayout>  
</LinearLayout>  
至此,便可通過ListAdapter來實現程式中之Adapter代碼如下: 
package com.wenbin.test;

import java.util.Iterator;
import java.util.Set;

import com.wenbin.test.site.Blog;
import android.content.Context;
import android.database.DataSetObserver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.Adapter;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.TextView;

public class BlogAdapter implements ListAdapter {
      private static final String AT = "@";   
      private static final String COLON=": ";
     
      private Set<Blog> blogs;
      private Context context;
     
      public BlogAdapter(Set<Blog> blogs,Context context){
             this.blogs=blogs;
             this.context=context;
      }

      @Override
      public boolean areAllItemsEnabled() {
             return true;
      }

      @Override
      public boolean isEnabled(int arg0) {
             return true;
      }

      @Override
      public int getCount() {
             return blogs.size();
      }

      @Override
      public Blog getItem(int position) {
             if (position<0 || position>=getCount())
                   return null;
     
             if (blogs!=null){
                   Iterator<Blog> iterator=blogs.iterator();
                   int i=0;
                   while(iterator.hasNext()){
                          if (i==position){
                                return iterator.next();
                          }
                          else{
                                iterator.next();
                                i++;
                          }
                   }
             }
             return null;
      }

      @Override
      public long getItemId(int position) {
             return 0;
      }

      @Override
      public int getItemViewType(int position) {
             return Adapter.IGNORE_ITEM_VIEW_TYPE;
      }

      @Override
      public View getView(int position, View convertView, ViewGroup parent) {
             View view=null;
             if (convertView==null){
                   LayoutInflater li=LayoutInflater.from(context);
                   view=li.inflate(R.layout.blogview, null);
             }
             else{
                   view=convertView;
             }

             Blog blog=getItem(position);
             if (blog!=null){
                   updateBlogView(view, blog);
                  
                   if (blog.isHaveRetweetedBlog()&& blog.getInReplyBlogText().length()>0){
                          updateRetweeteBlogView(view, blog);
                   }
                   else{
                          view.findViewById(R.id.reBlog).setVisibility(View.GONE);
                          view.findViewById(R.id.reImage).setVisibility(View.GONE);
                   }
             }
             view.setTag(blog);
             return view;
      }

      /**
       * @param view
       * @param blog
       */
      private void updateBlogView(View view, Blog blog) {
             TextView userName=(TextView)view.findViewById(R.id.userName);
             TextView blogText=(TextView)view.findViewById(R.id.blogText);
             WebView profileImage=(WebView)view.findViewById(R.id.profileImage);
             ImageView vImage=(ImageView)view.findViewById(R.id.vImage);
             WebView smallImage=(WebView)view.findViewById(R.id.smallImage);
             TextView sourceText=(TextView)view.findViewById(R.id.sourceText);

             userName.setText(blog.getUser().getScreenName());
             sourceText.setText(context.getString(R.string.from)+blog.getSource());
                  
             blogText.setText(blog.getText());
             profileImage.loadUrl(blog.getUser().getProfileImageUrl());
            
             if (!blog.getUser().isVerified())
                   vImage.setVisibility(View.INVISIBLE);
             if (blog.getSmallPic().length()>0){
                   smallImage.loadUrl(blog.getSmallPic());
             }
             else{
                   smallImage.setVisibility(View.GONE);
             }
      }

      /**
       * @param view
       * @param blog
       */
      private void updateRetweeteBlogView(View view, Blog blog) {
             TextView reBlogText=(TextView)view.findViewById(R.id.reBlogText);
             WebView reImage=(WebView)view.findViewById(R.id.reImage);

             if (blog.getInReplyBlogText().length()>0){
                   if (blog.getInReplyUserScreenName().length()>0){
                   reBlogText.setText(AT+blog.getInReplyUserScreenName()+COLON+blog.getInReplyBlogText());
                   }
                   else{
                          reBlogText.setText(blog.getInReplyBlogText());
                   }
             }
             else{
                   reBlogText.setVisibility(View.GONE);
             }
            
             if (blog.getRetweetedBlog().getSmallPic().length()>0){
                   reImage.loadUrl(blog.getRetweetedBlog().getSmallPic());
             }
             else{
                   reImage.setVisibility(View.GONE);
             }
      }

      @Override
      public int getViewTypeCount() {
             return 1; 
      }

      @Override
      public boolean hasStableIds() {
             return false;
      }

      @Override
      public boolean isEmpty() {
             return false;
      }

      @Override
      public void registerDataSetObserver(DataSetObserver observer) {

      }

      @Override
      public void unregisterDataSetObserver(DataSetObserver observer) {

      }

} 
完成之後運行一下程式看看介面顯示結果是否合乎預期,如下圖所示:
結果觀察分析:初具雛形,但尚差某些細節須再補足,如:表情符未顯示、@昵稱未高亮顯示、URL未展現成連結、圖片的週邊有白框、圖片下載過程中無默認背景。 
現在ListView已經有了基本外觀,且能夠顯示用戶名的微博內容,但未能把URL@符號以特殊的外觀顯示出來。對於URL的顯示,可針對TextViewAutoLinkMask屬性進行設置,如此便可URL展示為連結(如正確的識別郵箱位址和電話號碼等連結)
至於對“@昵稱”這樣的形式,僅僅通過設置AutoLinkMask是不能被識別出來的,因為這顯示符號不在它能自動識別連結的格式規則之內。思路:那麼如何處理這種元素呢?可分成兩步驟來考慮,一是識別這種形態,另一是用特殊的顏色表現出來
首先是識別,此處用最簡單的辦法進行了識別的過程,即找到‘@’符號,再向後在一定範圍內找到‘:’或‘ (空格),介於這中間的字元即是識別出來的部分,但注意此方式顯然不能涵蓋所有的情況。
然後是表現,如果想在TextView中對部分文字使用特別的顏色,最便捷的方式就是使用HTML元素,即通過為其添加<Font>標籤來影響Android的渲染。
進行上述兩步驟之編碼作業,TextView繼承一個子類BlogTextView,改寫其中的setText()方法,先對設置進來的文本進行保存,然後識別出其中的“@昵稱”形式,識別好以後為其加入<Font>標籤,再利用基類的SetText()方法進行處理,當然,也不能忘了為其打開AutoLinkMask,還有改寫getText()方法以返回類別中保存的原始文本資訊。代碼如下: 
package com.wenbin.test;

import java.util.Map;
import java.util.Set;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.text.Html.ImageGetter;
import android.text.util.Linkify;
import android.util.AttributeSet;
import android.widget.TextView;

public class BlogTextView extends TextView {
private static final int NAMELENGTH=15; //假设昵称不超过15个字符
private CharSequence text;

public BlogTextView(Context context) {
       super(context);
       setAutoLinkMask(Linkify.ALL);
}

public BlogTextView(Context context, AttributeSet attrs) {
       super(context, attrs);
       setAutoLinkMask(Linkify.ALL);
}

public BlogTextView(Context context, AttributeSet attrs, int defStyle) {
       super(context, attrs, defStyle);
       setAutoLinkMask(Linkify.ALL);
}
@Override
public CharSequence getText() {
       return text==null?"":text;
}

@Override
public void setText(CharSequence text, BufferType type) {
       this.text=text;
      
       String cs=text.toString();
       String font1="<font color=#339966>";
       String font2="</font>";
      
       //找以'@'开头以':'' '结尾的子串,将其使用font标记进行修饰
       int start=0;
       while(true){
              start=cs.indexOf('@',start);
              if (start<cs.length() && start>=0){
                    int end=cs.indexOf(' ',start);
                    if (end<cs.length() && end>0 && end-start<=NAMELENGTH){
                          CharSequence subcs=new String(cs.subSequence(start, end).toString());
                           cs=cs.replace(subcs,font1+subcs+font2 );
                          start+=font1.length()+subcs.length()+font2.length();
                    }
                    else{
                          end=cs.indexOf(':',start);
                          if (end<cs.length() && end>0 && end-start<=NAMELENGTH){
                                 CharSequence subcs=new String(cs.subSequence(start, end).toString());
                                 cs=cs.replace(subcs,font1+subcs+font2 );
                                 start+=font1.length()+subcs.length()+font2.length();
                          }
                    }
                    start+=1;
              }
              else{
                    break;
              }
       }
      
       super.setText(Html.fromHtml(cs), type);
}
}
完成代碼之後,重新把資源檔blogview.xmlidblogTextreBlogTextTextView改為com.wenbin.test.BlogTextView,這是使用自訂控制項的方法(此種技巧前述文章有使用過)。下列展示之片斷代碼為以idblogText為例之修改對照(記得亦為idreBlogText作修改):
    <com.wenbin.test.BlogTextView android:id="@+id/blogText" android:layout_height="wrap_content"  
    android:layout_below="@+id/userName"  
    android:textColor="@color/black"  
    android:textSize="15sp" android:layout_width="wrap_content">  
</com.wenbin.test.BlogTextView>  
重新運行程式,效果顯示如下圖所示:
<<下回再續>>

0 意見: