打造高仿QQ的友盟反饋界面(MVP模式)

什麼是MVP呢,簡單來講就是將view層和邏輯徹底獨立出來,讓邏輯和顯示徹底獨立。本例中就是採用了這種模式,讓activity做爲view層,activity中涉及了適配器,因此這裏嘗試讓適配器做爲P層來進行邏輯處理。之後可能要考慮用多個p來作邏輯處理。總之,咱們先來分析下如何用MVP得思路來分析這個工程吧~html

1、界面java

界面這個環節有不少細節須要扣,以前我寫過一篇文章就是講這個界面實現的,推薦先去看看:http://www.cnblogs.com/tianzhijiexian/p/4295195.htmlandroid

 

2、根據界面來思考邏輯git

通常狀況下咱們從設計那裏獲得了一張圖後就須要進行分析了,分析這個界面須要什麼邏輯。因此咱們再來看看界面是什麼樣的:github

 

咱們從上到下進行分析,分析時就須要寫出接口了,等於把天然語言程序化。數組

1.頂部有退出按鈕——finish()服務器

2.頂部有刷新按鈕——refresh();刷新成功後須要有回調——onRefreshSuccess()app

3.界面有信息,須要適配器——setAdapter()
dom

4.下方有+號,是發送圖片的按鈕——sendPhoto();由於是實時聊天界面,即便信息沒發送成功,也須要添加到適配器中,顯示一個無法送成功的標記就好。因此不須要作回調。只須要在適配器的getView()中根據list得item的標誌來判斷是否發送成功了,根據是否發送成功來顯示無法送成功的感嘆號。
ide

5.有發送按鈕,發送文字——addNewReply(String str);由於是實時聊天界面,即便信息沒發送成功,也須要添加到適配器中,顯示一個無法送成功的標記就好。須要在適配器的getView()中進行狀態的回調,回調方式同上。

6.既然須要在getView中進行回調,那麼activity中就要能有這個getView()的方法——onGetViewFromAdapter()

 

3、Activity須要實現的接口

這樣咱們大概的接口就已經寫好了,下面來看看最終的接口文檔:

接口 IUMengFeedbackView(實現友盟反饋的activity須要實現這個接口)

 

4、調用P層進行邏輯操做

咱們假設咱們的activity已經實現了這個接口,也已經作好了界面,那麼是否是該調用p層來處理邏輯了呢?如今p層在哪裏呢?彆着急,p我已經寫好了,並且對外提供了不少的方法讓view能夠隨意調用。

UMengFeedbackPresenter的源碼:

package com.kale.umenglib;

import com.umeng.fb.FeedbackAgent;
import com.umeng.fb.SyncListener;
import com.umeng.fb.model.Conversation;
import com.umeng.fb.model.Reply;

import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import java.util.List;
import java.util.UUID;

/**
 * @author:Jack Tony
 * 定義回話界面的adapter
 * @date :2015年2月9日
 */
public class UMengFeedbackPresenter extends BaseAdapter {

    private final String TAG = getClass().getSimpleName();

    /**
     * 表示是一對一聊天,有兩個類型的信息
     */
    private static final int VIEW_TYPE_COUNT = 2;

    /**
     * 用戶的標識
     */
    private static final int VIEW_TYPE_USER = 0;

    /**
     * 開發者的標識
     */
    private static final int VIEW_TYPE_DEV = 1;

    /**
     * 一次性加載多少條數據,默認10條
     */
    private int mLoadDataNum = 10; // default

    /**
     * 當前顯示的數據條數
     */
    private int mCurrentMsgCount = 10;

    private Context mContext;

    /**
     * 負責顯示umeng反饋界面信息的activity
     */
    private IUMengFeedbackView mFeedbackView;

    /**
     * 反饋系統的回話對象
     */
    private Conversation mConversation;

    private static UMengFeedbackPresenter instance;

    private UMengFeedbackPresenter(IUMengFeedbackView view) {
        mContext = (Context) view;
        mFeedbackView = view;
        mConversation = new FeedbackAgent(mContext).getDefaultConversation();
        mConversation.setOnChangeListener(new Conversation.OnChangeListener() {

            @Override
            public void onChange() {
                // 發送消息後會自動調用此方法,在這裏更新下發送狀態
                notifyDataSetChanged();
            }
        });
    }

    public static UMengFeedbackPresenter getInstance(IUMengFeedbackView view) {
        if (instance == null) {
            instance = new UMengFeedbackPresenter(view);
        }
        return instance;
    }

    /**
     * 獲得當前adapt中的數據條數
     *
     * @return 當前adapt中的數據條數
     */
    @Override
    public int getCount() {
        // 若是開始時的數目小於一次性顯示的數目,就按照當前的數目顯示,不然會數組越界
        int totalCount = mConversation.getReplyList().size();
        if (totalCount < mCurrentMsgCount) {
            mCurrentMsgCount = totalCount;
        }
        return mCurrentMsgCount;
    }

    /**
     * @return 當前的position
     * 重要方法,計算出當前的position
     */
    private int getCurrentPosition(int position) {
        int totalCount = mConversation.getReplyList().size();
        if (totalCount < mCurrentMsgCount) {
            mCurrentMsgCount = totalCount;
        }
        return totalCount - mCurrentMsgCount + position;
    }

    @Override
    public Object getItem(int position) {
        position = getCurrentPosition(position);
        return mConversation.getReplyList().get(position);
    }

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


    @Override
    public int getViewTypeCount() {
        // 這裏是一對一聊天,因此是兩種類型
        return VIEW_TYPE_COUNT;
    }

    @Override
    public int getItemViewType(int position) {
        position = getCurrentPosition(position);
        // 獲取單條回覆
        Reply reply = mConversation.getReplyList().get(position);
        if (reply.type.equals(Reply.TYPE_DEV_REPLY)) {
            // 開發者回覆Item佈局
            return VIEW_TYPE_DEV;
        } else if (reply.type.equals(Reply.TYPE_USER_REPLY)) {
            // 用戶反饋、回覆Item佈局
            return VIEW_TYPE_USER;
        } else {
            return 0;
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        position = getCurrentPosition(position);
        // 獲得當前位置的reply對象
        Reply reply = mConversation.getReplyList().get(position);
        //Log.d(TAG, "reply type = " + reply.type);
        if (convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(mContext);
            // 根據Type的類型來加載不一樣的Item佈局
            switch (reply.type) {
                case Reply.TYPE_DEV_REPLY:
                    // 若是是開發者回覆的,那麼就加載開發者回覆的佈局
                    convertView = inflater.inflate(mFeedbackView.getDevReplyLayoutId(), null);
                    break;
                case Reply.TYPE_NEW_FEEDBACK:
                    //break;
                case Reply.TYPE_USER_REPLY:
                    convertView = inflater.inflate(mFeedbackView.getUserReplyLayoutId(), null);
                    break;
                default:
            }
        }

        if (reply.type.equals(Reply.TYPE_USER_REPLY) || reply.type.equals(Reply.TYPE_NEW_FEEDBACK)) {
            mFeedbackView.setUserReplyView(convertView, reply);
        } else if (reply.type.equals(Reply.TYPE_DEV_REPLY)) {
            mFeedbackView.setDevReplyView(convertView, reply);
        }

        Reply nextReply = null;
        if ((position + 1) < mConversation.getReplyList().size()) {
            nextReply = mConversation.getReplyList().get(position + 1);
        }
        mFeedbackView.onGetViewFromAdapter(convertView, reply, nextReply);
        return convertView;
    }

    /**
     * 加載以前的聊天信息
     */
    public void loadOldData() {
        int loadDataNum = mLoadDataNum;
        int totalCount = mConversation.getReplyList().size();
        if (loadDataNum + mCurrentMsgCount >= totalCount) {
            // 若是要加載的數據超過了數據的總量,算出實際加載的數據條數
            loadDataNum = totalCount - mCurrentMsgCount;
        }
        mCurrentMsgCount += loadDataNum;
        notifyDataSetChanged();
        mFeedbackView.onLoadOldDataSuccess(loadDataNum);
    }

    /**
     * 發送圖片給開發者
     */
    public void sendPhotoToDev() {
        Intent intent = new Intent();
        intent.putExtra(UMengFeedbackPhotoActivity.KEY_UMENG_GET_PHOTO, UMengFeedbackPhotoActivity.VALUE_UMENG_GET_PHOTO);
        intent.setClass(mContext, UMengFeedbackPhotoActivity.class);
        mContext.startActivity(intent);
    }

    /**
     * 當用戶發送圖片信息時,在Activity的onActivityResult中調用此方法來處理上傳圖片等後續操做
     */
    protected void getPhotoFromAlbum(Intent data) {
        //Log.e(TAG, "data.getDataString -- " + data.getDataString());
        if (UMengB.a(mContext, data.getData())) {
            UMengB.a(mContext, data.getData(), "R" + UUID.randomUUID().toString(), new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    sendMsgToDev((String) msg.obj, Reply.CONTENT_TYPE_IMAGE_REPLY);
                }
            });
        }
    }

    /**
     * 用戶發送了一條新的信息後調用此方法
     *
     * @param replyMsg 信息的內容
     * @param type     Reply.CONTENT_TYPE_TEXT_REPLY或者Reply.CONTENT_TYPE_IMAGE_REPLY
     */
    public void sendMsgToDev(String replyMsg, String type) {
        if (type.equals(Reply.CONTENT_TYPE_TEXT_REPLY)) {
            mConversation.addUserReply(replyMsg);
        } else if (type.equals(Reply.CONTENT_TYPE_IMAGE_REPLY)) {
            mConversation.addUserReply("", replyMsg, "image_reply", -1.0F);
        } else if (type.equals(Reply.CONTENT_TYPE_AUDIO_REPLY)) {

        }
        mCurrentMsgCount++;
        syncToUmeng();
    }

    /**
     * 將數據和服務器同步
     * TODO:這裏有兩種寫法,能夠考慮換個實現方式。
     */
    public void syncToUmeng() {
        //new FeedbackAgent(mContext).sync();// 第一種寫法
        // 第二種寫法↓
        mConversation.sync(new SyncListener() {

            @Override
            public void onSendUserReply(List<Reply> replyList) {
                Log.d(TAG, "onSendUserReply");
                if (replyList == null || replyList.size() < 1) {
                    Log.d(TAG, "user 用戶沒有發送新的消息");
                } else {
                    notifyDataSetChanged();
                }
            }

            @Override
            public void onReceiveDevReply(List<Reply> replyList) {
                Log.d(TAG, "onReceiveDevReply");
                if (replyList == null || replyList.size() < 1) {
                    // 沒有開發者新的回覆
                    Log.d(TAG, "dev 開發者沒有新的回覆");
                } else {
                    notifyDataSetChanged();
                }
            }
        });
    }


    /**
     * 設置界面一開始顯示多少條數據,默認顯示最近的十條信息
     */
    public void setReplyMsgCount(int count) {
        mCurrentMsgCount = count;
    }

    /**
     * 設置調用loadOldData()時,一次性加載多少條數據,默認10條
     */
    public void setLoadDataNum(int number) {
        mLoadDataNum = number;
    }

    /**
     * 獲得適配器對象
     */
    public BaseAdapter getAdapter() {
        return this;
    }

}
shark0017

由於有發送圖片的功能因此須要從系統相冊中獲得圖片,這就要創建一個activity去獲取圖片:

package com.kale.umenglib;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.provider.MediaStore;

/**
 * @author Jack Tony
 * @date 2015/5/11
 */
public class UMengFeedbackPhotoActivity extends Activity{

    private static final int REQUEST_CODE = 1;

    public static final String KEY_UMENG_GET_PHOTO = "KEY_UMENG_GET_PHOTO";
    public static final int VALUE_UMENG_GET_PHOTO = 1;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getIntent() != null && getIntent().getIntExtra(KEY_UMENG_GET_PHOTO, 0) == VALUE_UMENG_GET_PHOTO) {
            Intent intent = new Intent("android.intent.action.PICK", MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            startActivityForResult(intent, REQUEST_CODE);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == -1 && requestCode == REQUEST_CODE && data != null) {
            UMengFeedbackPresenter.getInstance(null).getPhotoFromAlbum(data);
        }
        finish();
    }
}

 

5、Demo

下面的demo經過activity來調用了presenter的各個方法,徹底自定義的友盟的反饋界面,並且只用關係界面的view,不用考慮任何邏輯處理。這就是mvp的特色,分工明確,並且方便擴展~

UMengFeedbackActivity源碼:

package com.example.jack.umengfeedback;

import com.kale.lib.ViewHolder;
import com.kale.lib.activity.KaleBaseActivity;
import com.kale.lib.utils.EasyToast;
import com.kale.lib.utils.InputUtil;
import com.kale.umenglib.IUMengFeedbackView;
import com.kale.umenglib.UMengFeedbackPresenter;
import com.umeng.fb.model.Reply;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.ViewStub;
import android.view.WindowManager;
import android.widget.AbsListView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.text.SimpleDateFormat;
import java.util.Date;

public class UMengFeedbackActivity extends KaleBaseActivity implements IUMengFeedbackView {

    /**
     * 退出的文字按鈕
     */
    private TextView exitTv;

    /**
     * 刷新新的信息的圖片按鈕
     */
    private ImageView refreshIv;

    /**
     * 會話界面的下拉刷新控件
     */
    private SwipeRefreshLayout swipeRefreshLayout;

    /**
     * 對話的listView
     */
    private ListView conversationLv;

    /**
     * 輸入信息的文本框
     */
    private EditText inputBoxEt;

    /**
     * 發送信息的按鈕
     */
    private Button sendMsgBtn;

    private ImageView sendPhotoIv;

    /**
     * 友盟反饋界面的聊天信息適配器
     */
    private UMengFeedbackPresenter mUMengFeedbackPresenter;


    @Override
    protected void beforeSetContentView() {
        super.beforeSetContentView();
    }

    @Override
    protected int getContentViewId() {
        return R.layout.umeng_feedback_main;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }


    /**
     * 當這個activity在最上方時不重複啓動activity, 若是調用了startActivity,那麼就更新下視圖
     */
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.d(TAG, "on new intent");
    }

    @Override
    protected void findViews() {
        refreshIv = getView(R.id.refresh_imageView);
        exitTv = getView(R.id.exit_textView);
        swipeRefreshLayout = getView(R.id.swipe_container);
        conversationLv = getView(R.id.fb_conversation_listView);
        inputBoxEt = getView(R.id.inputBox_editText);
        sendMsgBtn = getView(R.id.sendMsg_button);
        sendPhotoIv = getView(R.id.sendPhoto_imageView);
    }

    @Override
    protected void beforeSetViews() {
        mUMengFeedbackPresenter = UMengFeedbackPresenter.getInstance(this);
    }

    @Override
    protected void setViews() {
        refreshIv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO:修復bug:只有少數信息時,刷新開發者的回覆後listView會跳到頂端
                mUMengFeedbackPresenter.syncToUmeng();
                EasyToast.makeText(mContext, "刷新成功~");
            }
        });
        exitTv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        setSwipeLayout();
        setConversationListView();
        setInputBoxEditText();
        /**
         * 設置發送按鈕的事件
         */
        sendMsgBtn.setEnabled(false);
        sendMsgBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                sendMessage();
            }
        });
        /**
         * 設置添加圖片按鈕的事件
         */
        sendPhotoIv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mUMengFeedbackPresenter.sendPhotoToDev();
                conversationLv.setSelection(mUMengFeedbackPresenter.getAdapter().getCount());
            }
        });
    }

    /**
     * 設置下拉刷新的控件
     */
    private void setSwipeLayout() {
        swipeRefreshLayout.setSize(SwipeRefreshLayout.DEFAULT);
        // 設置下拉圓圈上的顏色,藍色、綠色、橙色、紅色
        swipeRefreshLayout.setColorSchemeResources(
                android.R.color.holo_blue_bright,
                android.R.color.holo_green_light,
                android.R.color.holo_orange_light,
                android.R.color.holo_red_light);
        swipeRefreshLayout.setOnRefreshListener(new OnRefreshListener() {

            @Override
            public void onRefresh() {
                mUMengFeedbackPresenter.loadOldData();
                conversationLv.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_NORMAL);
            }
        });
    }

    /**
     * 當加載舊的數據完成後的回調方法
     *
     * @param loadDataNum 加載了多少箇舊的數據
     */
    @Override
    public void onLoadOldDataSuccess(int loadDataNum) {
        swipeRefreshLayout.setRefreshing(false);
        // 加載完畢舊的數據,跳到刷新出來數據的位置
        if (loadDataNum - 1 >= 0) {
            conversationLv.setSelection(loadDataNum - 1);
        } else {
            EasyToast.makeText(mContext, "已經到頭了");
            conversationLv.setSelection(0);
        }
        conversationLv.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
    }

    /**
     * 設置listView,list不顯示分割線,設置滾動監聽器,設置適配器
     */
    private void setConversationListView() {
        conversationLv.setDivider(null);
        conversationLv.setAdapter(mUMengFeedbackPresenter.getAdapter());
        // 不顯示滾動到頂部/底部的陰影(減小繪製)
        conversationLv.setOverScrollMode(View.OVER_SCROLL_NEVER);
        // 監聽listView的滑動狀態,若是到了頂部就刷新數據,向上滑動就隱藏輸入法
        conversationLv.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}

            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                switch (scrollState) {
                    case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
                        // 滾動中止
                        if (view.getLastVisiblePosition() == (view.getCount() - 1)) {
                            // 若是滾動到底部
                        } else if (view.getFirstVisiblePosition() == 0) {
                            // 滾動到頂部
                        }
                        break;
                    case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
                        // 開始滾動
                        break;
                    case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
                        // 正在滾動
                        InputUtil.getInstance((Activity) mContext).hide();
                        break;
                }
            }
        });
    }


    /**
     * 設置發送消息的按鈕和輸入框 按下回車鍵,發送消息
     */
    private void setInputBoxEditText() {

        inputBoxEt.setOnKeyListener(new OnKeyListener() {

            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                // 按下回車發送消息
                // 這兩個條件必須同時成立,若是僅僅用了enter判斷,就會執行兩次
                if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN) {
                    sendMessage();
                    return true;
                }
                return false;
            }
        });
        // 給editText添加監聽器
        inputBoxEt.addTextChangedListener(new TextWatcher() {

            // 輸入過程當中,還在內存裏,沒到屏幕上
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            // 在輸入以前會觸發的
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void afterTextChanged(Editable s) {
                // 輸入完將要顯示到屏幕上時會觸發
                boolean isEmpty = s.toString().isEmpty();
                sendMsgBtn.setEnabled(!isEmpty);
                sendMsgBtn.setTextColor(isEmpty ? 0xffa1a2a5 : 0xffffffff);
            }
        });
    }

    /**
     * 發送消息
     */
    private void sendMessage() {
        String replyMsg = inputBoxEt.getText().toString();
        inputBoxEt.getText().clear();
        if (!TextUtils.isEmpty(replyMsg)) {
            mUMengFeedbackPresenter.sendMsgToDev(replyMsg, Reply.CONTENT_TYPE_TEXT_REPLY);
            conversationLv.setSelection(mUMengFeedbackPresenter.getAdapter().getCount());
        }
    }

    @Override
    public int getUserReplyLayoutId() {
        return R.layout.umeng_feedback_user_reply;
    }

    /**
     * 設置用戶的list item view
     * 這裏的提示信息有進度條和感嘆號兩種。若是正在發送就顯示進度條,若是發送失敗就顯示感嘆號
     */
    @Override
    public void setUserReplyView(View convertView, Reply reply) {
        // 利用viewHolder進行了優化
        TextView textMsgTv = ViewHolder.get(convertView, R.id.textMsg_textView);
        ImageView photoMsgIv = ViewHolder.get(convertView, R.id.photoMsg_imageView);
        ImageView msgErrorIv = ViewHolder.get(convertView, R.id.msg_error_imageView);
        ProgressBar msgSendingPb = ViewHolder.get(convertView, R.id.msg_progressBar);
        // 放入消息
        switch (reply.content_type) {
            case Reply.CONTENT_TYPE_TEXT_REPLY:
                photoMsgIv.setVisibility(View.GONE);
                textMsgTv.setVisibility(View.VISIBLE);
                textMsgTv.setText(reply.content);
                break;
            case Reply.CONTENT_TYPE_IMAGE_REPLY:
                textMsgTv.setVisibility(View.GONE);
                photoMsgIv.setVisibility(View.VISIBLE);
                // 顯示大圖
                //photoMsgIv.setImageBitmap(BitmapFactory.decodeFile(com.umeng.fb.util.c.b(mContext, reply.reply_id)));
                // 顯示小圖
                com.umeng.fb.image.a.a().a(com.umeng.fb.util.c.b(mContext, reply.reply_id), photoMsgIv, getPhotoSize(mContext));
                break;
            case Reply.CONTENT_TYPE_AUDIO_REPLY:

                break;
            default:
        }

        // 根據Reply的狀態來設置replyStateFailed的狀態,若是發送失敗就顯示提示圖標
        switch (reply.status) {
            case Reply.STATUS_NOT_SENT:
                msgSendingPb.setVisibility(View.GONE);
                msgErrorIv.setVisibility(View.VISIBLE);
                break;
            case Reply.STATUS_SENDING:
                //break;
            case Reply.STATUS_WILL_SENT:
                msgSendingPb.setVisibility(View.VISIBLE);
                msgErrorIv.setVisibility(View.GONE);
                break;
            case Reply.STATUS_SENT:
                msgSendingPb.setVisibility(View.GONE);
                msgErrorIv.setVisibility(View.GONE);
                break;
            default:
        }
    }

    @Override
    public int getDevReplyLayoutId() {
        return R.layout.umeng_feedback_dev_reply;
    }
    
    /**
     * 設置開發者的list item view
     */
    @Override
    public void setDevReplyView(View convertView, Reply reply) {
        // 利用viewHolder進行了優化
        TextView textMsgTv = ViewHolder.get(convertView, R.id.dev_textMsg_textView);
        textMsgTv.setText(reply.content);
    }


    /**
     * 若是兩條信息間隔了TIME_RANGE秒,那麼就顯示上一條信息的發送時間
     */
    public static final int TIME_RANGE = 2 * 60;

    @Override
    public void onGetViewFromAdapter(View convertView, Reply reply, Reply nextReply) {
       /* Log.d(TAG, "context_type = " + reply.content_type);
        Log.d(TAG, "context = " + reply.content);
        Log.d(TAG, "reply_id = " + reply.reply_id);*/

        // 顯示消息的時間
        if (nextReply != null) {
            ViewStub timeView = ViewHolder.get(convertView, R.id.msg_time_viewStub);
            // 當兩條回覆相差TIME_RANGE秒時顯示時間
            if (nextReply.created_at - reply.created_at > TIME_RANGE * 1000) {
                timeView.setVisibility(View.VISIBLE);
                TextView timeTv = ViewHolder.get(convertView, R.id.msg_Time_TextView);
                Date replyTime = new Date(reply.created_at);
                SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
                timeTv.setText(sdf.format(replyTime));
            } else {
                timeView.setVisibility(View.GONE);
            }
        }
    }

    private int getPhotoSize(Context context) {
        DisplayMetrics metrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(metrics);
        return metrics.widthPixels > metrics.heightPixels ? metrics.heightPixels : metrics.widthPixels;
    }

    @Override
    public void finish() {
        super.finish();
        InputUtil.getInstance((Activity) mContext).hide();
    }
}

 

源碼下載:

http://download.csdn.net/detail/shark0017/8683945

最新源碼(推薦):http://download.csdn.net/detail/shark0017/8686989

BTW:源碼引用了kaleLibrary這個庫:https://github.com/tianzhijiexian/KaleLibrary/

相關文章
相關標籤/搜索