本文為菜鳥窩作者劉婷的連載。”商城項目實戰”系列來聊聊仿”京東淘寶的購物商城”如何實現。
商城項目中有主要的5大模塊,分別為主頁模塊、熱門模塊、分類模塊、購物車模塊以及我的模塊,其中我的模塊的主要功能是顯示用戶信息,里面包含了用戶頭像、我的訂單、我的收藏、收貨地址以及我的消息等,如下圖所示。

因為現在很多的賬號頭像都是圓形頭像,而且圓形頭像也更為的美觀些,所以本項目中我的頭像也是圓形頭像,那么這個圓形頭像是如何實現的呢?另外我的頭像下面還有個“點擊登錄”的文本,也就是還有登錄后的顯示效果嗎?帶著疑問往下看。
實現圓形頭像
實現用戶頭像為圓形頭像需要借助于第三方的開源控件 CircleImageView,這是一款 Android 開源顯示圓形圖像的控件,目前已經開源到了 GitHub 上面,具體的源代碼可以進入 Github 源碼查看。
1. CircleImageView 的相關屬性
CircleImageView 作為自定義的開源控件,主要有四大自定義的屬性,分別如下。
<declare-styleable name="CircleImageView">
<attr name="civ_border_width" format="dimension" />
<attr name="civ_border_color" format="color" />
<attr name="civ_border_overlay" format="boolean" />
<attr name="civ_fill_color" format="color" />
</declare-styleable>
其中 civ_border_width 是設置圖像外部邊框寬度,civ_border_color 表示圖像外部邊框顏色,civ_border_overlay 是一個 boolean 值, false 代表邊框是繪制在圖片外部,不覆蓋圖片最外層,true 則是在圖片之上繪制,覆蓋最外層,civ_fill_color 默認為透明,表示圖像填充的顏色。
2. CircleImageView 的使用方法
CircleImageView 的使用方法很簡單,而且該控件在目前主流的 Android 設備上面的顯示效果都很不錯,和之前使用第三方框架一樣的,首先要集成 CircleImageView。
2.1 Gradle 添加 CircleImageView 依賴
集成 CircleImageView 就是要在 module 的 build.gradle 文件中添加對 CircleImageView 的依賴。
dependencies {
......
compile 'de.hdodenhof:circleimageview:2.1.0'
}
添加好了依賴,就可以開始使用 CircleImageView 開源控件了。
2.2 布局中添加 CircleImageView
CircleImageView 作為一款開源控件,和其他的 Android 控件的使用方法一樣,直接在布局文件 layout 文件中添加該控件。
<de.hdodenhof.circleimageview.CircleImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/profile_image"
android:layout_width="96dp"
android:layout_height="96dp"
android:src="@drawable/profile"
app:civ_border_width="2dp"
app:civ_border_color="#FF000000"/>
將 CircleImageView 添加到布局文件中,同時對控件的相應屬性進行設置,布局中添加好了 CircleImageView 控件后,將布局在 Activity/Fragment 中加載即可。
實現我的模塊
我的模塊的布局比較簡單,同樣的功能也不復雜,結合上文介紹的 CircleImageView 來實現我的模塊。
1. 設計我的模塊布局
根據上文效果圖中可以看出,布局中需要有個顯示圖片的 ImageView以及下面4個列表,布局最好是簡單化比較好,所以在這里下面的4個列表就直接使用 TextView 實現就好。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_color">
<FrameLayout
android:id="@+id/mine_layout_head"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="?attr/colorPrimary" >
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/mine_img_head"
android:layout_width="@dimen/mine_img_head_width"
android:layout_height="@dimen/mine_img_head_width"
android:layout_gravity="center_horizontal"
android:layout_marginTop="12dp"
app:civ_border_width="2dp"
app:civ_border_color="#FFFFFF"
android:src="@mipmap/default_head">
</de.hdodenhof.circleimageview.CircleImageView>
<TextView
android:id="@+id/mine_tv_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="60dp"
android:layout_marginBottom="9dp"
android:gravity="center"
android:text="@string/to_login"
android:textColor="@color/white"
android:textSize="16sp" />
</FrameLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/mine_list_info_margin_top"
android:orientation="vertical">
<TextView
android:id="@+id/mine_tv_my_orders"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/largePadding"
android:background="@drawable/selector_list_item"
android:drawableLeft="@mipmap/icon_list_order"
android:gravity="center_vertical"
android:drawablePadding="20dp"
android:text="@string/my_orders"
android:textColor="@color/black"/>
<View style="@style/line_vertical"/>
<TextView
android:id="@+id/mine_tv_favorite"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/largePadding"
android:background="@drawable/selector_list_item"
android:drawableLeft="@mipmap/icon_favorite"
android:gravity="center_vertical"
android:drawablePadding="20dp"
android:text="@string/my_favorite"
android:textColor="@color/black"/>
<View style="@style/line_vertical"/>
<TextView
android:id="@+id/mine_tv_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/largePadding"
android:background="@drawable/selector_list_item"
android:drawableLeft="@mipmap/icon_location"
android:gravity="center_vertical"
android:drawablePadding="20dp"
android:text="@string/my_addresses"
android:textColor="@color/black"/>
<View style="@style/line_vertical"/>
<TextView
android:id="@+id/mine_tv_notification"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/largePadding"
android:background="@drawable/selector_list_item"
android:drawableLeft="@mipmap/icon_msg"
android:gravity="center_vertical"
android:drawablePadding="20dp"
android:text="@string/my_msg"
android:textColor="@color/black"/>
<Button
android:id="@+id/mine_btn_logout"
android:text="@string/logout"
style="@style/bigRedButton"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:layout_height="wrap_content"
android:layout_width="match_parent"
/>
</LinearLayout>
</ScrollView>
</LinearLayout>
總體布局設計還是狠清楚的,最后一個 Button 則是用來退出登錄的。
2. 加載用戶頭像
用戶頭像的數據也是網絡數據,加載用戶頭像,也就是獲取到圖像的 URL ,然后下載圖像,顯示在 CircleImageView 。
Picasso.with(getActivity()).load(url).into(imgHead);
圖像的下載就使用開源的 Picasso 圖像加載組件。
3. 添加頁面跳轉
上面的頭像部分完成了,下面就是下面的我的訂單、我的收藏、收貨地址以及我的消息的實現了,因為這四部分都是頁面的跳轉,所以只要為其添加好點擊事件監聽的處理——頁面跳轉。
private void initView() {
tvMyOders.setOnClickListener(this);
tvFavorite.setOnClickListener(this);
tvAddress.setOnClickListener(this);
tvNotification.setOnClickListener(this);
}
@Override
public void onClick(View view) {
if(view.getId() == R.id.mine_layout_head){
//我的訂單
}
else if(view.getId() == R.id.mine_tv_favorite){
//我的收藏
}
else if(view.getId() == R.id.mine_tv_address){
//收貨地址
}
else if(view.getId() == R.id.mine_tv_notification){
//我的消息
}
}
這里僅僅是頁面跳轉,至于我的訂單、我的收藏、收貨地址以及我的消息四大部分的具體實現后期會繼續介紹。
4.實現點擊登錄
點擊頭像上部區域,跳轉到登錄頁面,登錄的邏輯就先不要管了,登錄成功之后,自然要刷新頭像,并且修改頭像下的用戶名稱。
@Override
public void onClick(View view) {
if(view.getId() == R.id.mine_layout_head){
if(CNiaoApplicaiton.getInstance().getUser() == null) {
Intent intent = new Intent(getContext(), LoginActivity.class);
startActivityForResult(intent, Constants.REQUEST_CODE);
}
}
}
Constants.REQUEST_CODE 為請求碼,如果登錄成功了,則會設置 setResult(RESULT_OK); 并且回到我的頁面,這時候,我的頁面獲取到了來自登錄頁面的操作成功的結果碼的回調來刷新用戶信息,修改用戶信息的方法如下。
private void showUser(UserInfo user){
if(user!=null){
if(!TextUtils.isEmpty(user.getLogo_url()))
showHeadImage(user.getLogo_url());
tvUserName.setText(user.getUsername());
btnLoginOut.setVisibility(View.VISIBLE);
}
else {
imgHead.setImageResource(R.mipmap.default_head);
tvUserName.setText(R.string.to_login);
btnLoginOut.setVisibility(View.GONE);
}
}
UserInfo 為登錄后返回的用戶信息類,有用戶頭像、昵稱等成員。
5.實現退出登錄
退出登錄的話,就要把用戶的信息清理掉,然后刷新我的里面用戶信息的顯示。
CNiaoApplicaiton.getInstance().clearUser();
showUser(null);
clearUser() 方法是清理整個應用的用戶信息,等于當前用戶未登錄,showUser(UserInfo user) 是修改用戶信息的,退出了登錄,就傳空了,顯示用戶未登錄時我的頁面的情況。
6.效果圖
運行代碼,獲取效果圖。
上圖是登錄后的效果圖。
最終效果
最后來展示來最終的效果吧。
進入我的頁面,默認未登錄,點擊登錄,跳轉到登錄頁面,然后登錄成功,刷新顯示登錄的用戶頭像和昵稱等,再點擊退出登錄按鈕,我的頁面還原到未登錄效果。因為手機號啥的不好展示,所以就直接從登錄頁面到登錄成功后的我的頁面了。