友盟用戶反饋自定義UI-Android

友盟用戶反饋SDK是友盟爲開發者提供的組件之一,用戶反饋也是每款應用必不可少的模塊。如果你想方便的收集用戶的反饋建議,並且與發送反饋的用戶進行溝通交流,那麼友盟用戶反饋SDK是你不錯的選擇,使用友盟用戶反饋SDK兩行代碼實現開發者和用戶輕鬆高效溝通。從友盟BBS看到許多開發者都希望通過自定義UI,來實現用戶反饋功能。下面就爲大家來講解如何使用友盟用戶反饋SDK來制定UI。這裏以一個demo來說明。

首先上圖,這是自定義的UI界面:




注:部分資源文件來源於某開源App


使用友盟用戶反饋的數據接口,首先需要了解,SDK都提供了那些接口。根據集成文檔,我們可以知道,對於用戶反饋SDK來說,用戶和開發者或者客服交流的整個內容是一個Conversation,其中包含了用戶的反饋、追問以及客服的回覆,而整個Conversation是由Reply組成的,用戶的一條反饋或者是客服的一條回覆都是一個Reply,每個Reply都有一些屬性來表明Reply的各種信息。其中有:

type :

Reply.TYPE_DEV_REPLY            :  表示這是一條開發者的回覆

Reply.TYPE_SUER_REPLY            表示這是一條用戶的回覆

Reply.TYPE_NEW_FEEDBACK    :  表示這是一條反饋 相當於用戶的第一條回覆


status:

Reply.STATUS_NOT_SENT         :表示該條回覆沒有發送成功或者還未發送

Reply.STATUS_SENDING            :表示該條回覆正在發送

Reply.STATUS_SENT                   :表示該條回覆已發送成功


created_at : 表示回覆的時間,以毫秒爲單位

Conversation類提供了getReplyList()方法來獲取整個會話的內容,返回的是List<Reply>,同時也提供了addUserReply()方法,將用反饋內容加入到Conversation,那麼Conversation實例怎麼得到呢?

FeedbackAgent類中提供了一個getDefaultConversation()方法來獲取默認的Conversation(),對於不需要創建多個會話的App來講有這個就夠了。

最重要的一個接口:

Comversation.sync()方法,該方法實現了數據的同步,即可以通過該方法發送用戶反饋、回覆也可以通過該方法獲取來自開發者的回覆。下面會詳細介紹。

另外FeedbackAgent接口也提供了setUserInfo()方法來設置用戶信息,以及getUserInfo()方法獲取用戶信息,關於用戶信息的操作方法可以查看友盟用戶反饋SDK集成文檔,這裏不做演示。

瞭解了這些,下面我們就開始噼裏啪啦敲代碼。


第一步當然是佈局了,下面是自定義會話界面的佈局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:id="@+id/fb_input_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="vertical" >

        <View
            android:layout_width="match_parent"
            android:layout_height="@dimen/umeng_fb_item_line_height"
            android:background="@color/umeng_fb_line" />

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:clickable="true"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:orientation="horizontal"
            android:paddingBottom="8dp"
            android:paddingLeft="15dp"
            android:paddingRight="15dp"
            android:paddingTop="8dp" >

            <Button
                android:id="@+id/fb_send_btn"
                android:layout_width="70dp"
                android:layout_height="33dp"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:background="@drawable/fb_send_btn_bg"
                android:gravity="center"
                android:text="@string/umeng_fb_send"
                android:textColor="@android:color/white"
                android:textSize="16sp" />

            <EditText
                android:id="@+id/fb_send_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginRight="10dp"
                android:layout_toLeftOf="@id/fb_send_btn"
                android:layout_toStartOf="@id/fb_send_btn"
                android:background="@drawable/fb_input_bg"
                android:hint="@string/umeng_fb_feedback"
                android:minHeight="33dp"
                android:paddingLeft="10dp"
                android:paddingRight="10dp"
                android:scrollbars="vertical"
                android:textSize="16sp" />
        </RelativeLayout>
    </LinearLayout>

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/fb_reply_refresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/fb_input_layout" >

        <ListView
            android:id="@+id/fb_reply_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:divider="@null"
            android:listSelector="#00000000" >
        </ListView>
    </android.support.v4.widget.SwipeRefreshLayout>

</RelativeLayout>

佈局文件就不多說了,這裏包含了一個ListView來展示整個會話內容,還有一個輸入框和發送按鈕。

然後在Activity中開始利用友盟用戶反饋SDK的數據接口幹活。

要實現UI,這些View自然是少不了的

mListView = (ListView) findViewById(R.id.fb_reply_list);
sendBtn = (Button) findViewById(R.id.fb_send_btn);
inputEdit = (EditText) findViewById(R.id.fb_send_content);
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.fb_reply_refresh);

獲取Conversation對象,所有會話數據都在這裏

Conversation mComversation = new FeedbackAgent(this).getDefaultConversation();

然後爲ListView創建Adapter,代碼比較簡單,直接看註釋吧

class ReplyAdapter extends BaseAdapter {

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

		@Override
		public Object getItem(int arg0) {
			return mComversation.getReplyList().get(arg0);
		}

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

		@Override
		public int getViewTypeCount() {
			// 兩種不同的Item佈局
			return VIEW_TYPE_COUNT;
		}

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

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			ViewHolder holder = null;
			// 獲取單條回覆
			Reply reply = mComversation.getReplyList().get(position);
			if (convertView == null) {
				// 根據Type的類型來加載不同的Item佈局
				if (Reply.TYPE_DEV_REPLY.equals(reply.type)) {
					// 開發者的回覆
					convertView = LayoutInflater.from(mContext).inflate(
							R.layout.custom_fb_dev_reply, null);
				} else {
					// 用戶的反饋、回覆
					convertView = LayoutInflater.from(mContext).inflate(
							R.layout.custom_fb_user_reply, null);
				}

				// 創建ViewHolder並獲取各種View
				holder = new ViewHolder();
				holder.replyContent = (TextView) convertView
						.findViewById(R.id.fb_reply_content);
				holder.replyProgressBar = (ProgressBar) convertView
						.findViewById(R.id.fb_reply_progressBar);
				holder.replyStateFailed = (ImageView) convertView
						.findViewById(R.id.fb_reply_state_failed);
				holder.replyData = (TextView) convertView
						.findViewById(R.id.fb_reply_date);
				convertView.setTag(holder);
			} else {
				holder = (ViewHolder) convertView.getTag();
			}

			// 以下是填充數據
			// 設置Reply的內容
			holder.replyContent.setText(reply.content);
			// 在App界面,對於開發者的Reply來講status沒有意義
			if (!Reply.TYPE_DEV_REPLY.equals(reply.type)) {
				// 根據Reply的狀態來設置replyStateFailed的狀態
				if (Reply.STATUS_NOT_SENT.equals(reply.status)) {
					holder.replyStateFailed.setVisibility(View.VISIBLE);
				} else {
					holder.replyStateFailed.setVisibility(View.GONE);
				}

				// 根據Reply的狀態來設置replyProgressBar的狀態
				if (Reply.STATUS_SENDING.equals(reply.status)) {
					holder.replyProgressBar.setVisibility(View.VISIBLE);
				} else {
					holder.replyProgressBar.setVisibility(View.GONE);
				}
			}

			// 回覆的時間數據,這裏仿照QQ兩條Reply之間相差100000ms則展示時間
			if ((position + 1) < mComversation.getReplyList().size()) {
				Reply nextReply = mComversation.getReplyList()
						.get(position + 1);
				if (nextReply.created_at - reply.created_at > 100000) {
					Date replyTime = new Date(reply.created_at);
					SimpleDateFormat sdf = new SimpleDateFormat(
							"yyyy-MM-dd HH:mm:ss");
					holder.replyData.setText(sdf.format(replyTime));
					holder.replyData.setVisibility(View.VISIBLE);
				}
			}
			return convertView;
		}

		class ViewHolder {
			TextView replyContent;
			ProgressBar replyProgressBar;
			ImageView replyStateFailed;
			TextView replyData;
		}
	}


創建Adapter併爲ListView設置Adapter

adapter = new ReplyAdapter();
mListView.setAdapter(adapter);

會話列表完成了,接下來是發送反饋和App端與服務器數據的同步。

發送反饋

sendBtn.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				String content = inputEdit.getText().toString();
				inputEdit.getEditableText().clear();
				if (!TextUtils.isEmpty(content)) {
					// 將內容添加到會話列表
					mComversation.addUserReply(content);
					//刷新ListView
					adapter.notifyDataSetChanged();
					scrollToBottom();
					// 數據同步
					sync();
				}
			}
		});

下拉刷新操作

// 下拉刷新
mSwipeRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
			@Override
			public void onRefresh() {
				sync();
			}
		});


sync方法爲數據同步的方法,利用Comversation.sync方法來進行App端的數據與服務器端同步。該回調接口中onReceiveDevReply方法獲得的replyList爲開發者在友盟用戶反饋Web端的回覆。onSendUserReply方法獲得的replyList則爲本次同步數據中發送到服務器的用戶反饋數據列表

// 數據同步
private void sync() {

		mComversation.sync(new SyncListener() {

			@Override
			public void onSendUserReply(List<Reply> replyList) {
			}

			@Override
			public void onReceiveDevReply(List<Reply> replyList) {
				// SwipeRefreshLayout停止刷新
				mSwipeRefreshLayout.setRefreshing(false);
				// 刷新ListView
				adapter.notifyDataSetChanged();
				scrollToBottom();
			}
		});
	}

ListView Item的佈局比較簡單就不貼了,需要的話可以下載代碼查看。

到這裏一個利用友盟用戶反饋SDK自定義的UI就實現了。

工程下載地址


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章