MyFlag Step6:app详细页面设计与代码编写

引言

这周前半部分的工作我们主要对页面进行了初步设计,也实现了一些功能代码,后半部分在页面方面进行了进一步的详细设计,并且编写了其他功能代码,总结一下工作目录:

  • 页面详细设计与所有页面基本完成
  • 客户端代码编写
  • 后台代码编写

在这里,我对自己主要从事的工作,即客户端代码的编写,具体来说是查看好友界面及内部处理逻辑的编写,做一个着重的介绍。


一、界面编写


在之前的界面设计中,设计出的界面如下所示




经过分析,发现该界面的最主要的内容是好友的列表,因此考虑使用两个嵌套的ListView组件实现。但是,用户的分组是通过字母进行的,故外层的ListView实现起来会比较复杂。因此,我考虑自定义一个LetterFilterListView控件,继承ListView,实现了用侧边字母进行好友检索的功能,代码如下:


package com.example.sdu.myflag.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.SectionIndexer;
/**
 * 字母控件
 */
@SuppressWarnings("ResourceType")
public class LetterFilterListView extends RelativeLayout {

    /**
     * The context.
     */
    private Context mContext;

    /**
     * The section indexter.
     */
    private SectionIndexer mSectionIndexter = null;

    /**
     * The list view.
     */
    private ListView mListView;

    /**
     * The letter view.
     */
    private LetterView mLetterView;

    /**
     * The selectedLetter view
     */
    private LetterSelectedView mLetterSelectedView;

    public LetterFilterListView(Context context) {
        this(context, null);
    }

    public LetterFilterListView(Context context, AttributeSet attrs) {
        this(context, null, 0);
    }

    public LetterFilterListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context) {
        this.mContext = context;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        int count = getChildCount();
        /** 必须包括一个子 View */
        if (count < 1) {
            throw new IllegalArgumentException("this layout must contain 1 child views,and AdapterView  must in the first position!");
        }
        View view = this.getChildAt(0);
        AdapterView<?> adapterView = null;
        if (view instanceof AdapterView<?>) {
            adapterView = (AdapterView<?>) view;
            mListView = (ListView) adapterView;
            mSectionIndexter = (SectionIndexer) mListView.getAdapter();

            /** 右边的字母显示 */
            mLetterView = new LetterView(mContext);
            mLetterView.setListView(mListView);
            mLetterView.setId(5000);//为了下面的控件布局
            RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(60, ViewGroup.LayoutParams.WRAP_CONTENT);
            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
            layoutParams.topMargin = 10;
            layoutParams.rightMargin = 10;
            layoutParams.bottomMargin = 10;
            this.addView(mLetterView, layoutParams);

            /** 点击右边的字母后显示选中的字母 */
            mLetterSelectedView = new LetterSelectedView(mContext);
            RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams(30, ViewGroup.LayoutParams.WRAP_CONTENT);
            layoutParams1.topMargin = 10;
            layoutParams1.rightMargin = 10;
            layoutParams1.bottomMargin = 10;
            layoutParams1.addRule(RelativeLayout.LEFT_OF, mLetterView.getId());
            this.addView(mLetterSelectedView, layoutParams1);
        }
        /** 必须包括一个子 AdapterView,一般就是 ListView */
        if (adapterView == null) {
            throw new IllegalArgumentException("must contain a AdapterView in this layout!");
        }
    }

    /**
     * 右边字母显示 View
     *
     * @author liuyinjun
     * @date 2015-3-16
     */
    private class LetterView extends View {

        /**
         * The list.
         */
        private ListView mListView;

        /**
         * The letter.
         */
        private char[] mLetter;

        /**
         * The paint.
         */
        private Paint mPaint;

        /**
         * The width center.
         */
        private float mWidthCenter;

        /**
         * 字母之间的间距.
         */
        private float mSingleHeight;

        public LetterView(Context context) {
            this(context, null);
        }


        public LetterView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }


        public LetterView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init();
        }


        /**
         * 初始化.
         */
        private void init() {
            mLetter = new char[]{'#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
            mPaint = new Paint();
            mPaint.setColor(Color.parseColor("#949494"));
            mPaint.setTypeface(Typeface.DEFAULT_BOLD);
            mPaint.setTextSize(22);
            mPaint.setAntiAlias(true);
            mPaint.setTextAlign(Paint.Align.CENTER);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            float height = getHeight();
            mSingleHeight = height / mLetter.length;
            mWidthCenter = getMeasuredWidth() / (float) 2;
            for (int i = 0; i < mLetter.length; i++) {
                canvas.drawText(String.valueOf(mLetter[i]), mWidthCenter, mSingleHeight + (i * mSingleHeight), mPaint);
            }

        }

        /**
         * Gets the list view.
         *
         * @return the list view
         */
        public ListView getListView() {
            return mListView;
        }

        /**
         * Sets the list view.
         *
         * @param listView the new list view
         */
        public void setListView(ListView listView) {
            this.mListView = listView;
        }

        public boolean onTouchEvent(MotionEvent event) {
            super.onTouchEvent(event);
            int index = 0;//点击的位置在 mLetters 中的索引
            int i = (int) event.getY();
            int div = (int) mSingleHeight;
            /** 重新计算出索引 */
            if (div != 0) {
                index = i / div;
            }
            if (index >= mLetter.length) {
                index = mLetter.length - 1;
            } else if (index < 0) {
                index = 0;
            }

            switch (event.getAction()) {
                case MotionEvent.ACTION_UP:
                    break;
                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_MOVE:
                    mLetterSelectedView.setViewY(mSingleHeight + (index * mSingleHeight));//设置选中字母显示的Y轴坐标位置
                    mLetterSelectedView.setSelectedLetter(mLetter[index]);//设置选中的字母
                    if (mLetterSelectedView.getVisibility() == View.GONE)//若控件为隐藏状态,则显示
                        mLetterSelectedView.setVisibility(View.VISIBLE);
                    /** 显示1s后消失*/
                    mLetterSelectedView.postDelayed(new Runnable() {

                        @Override
                        public void run() {
                            // TODO Auto-generated method stub
                            mLetterSelectedView.setVisibility(View.GONE);
                        }
                    }, 1000);

                    if (mListView.getAdapter() != null) {
                        ListAdapter listAdapter = (ListAdapter) mListView.getAdapter();
                        if (mSectionIndexter == null) {
                            mSectionIndexter = (SectionIndexer) listAdapter;
                        }
                        int position = mSectionIndexter.getPositionForSection(mLetter[index]);

                        if (position == -1) {//列表中没有首字母为选中字母的的项
                            return true;
                        }
                        mListView.setSelection(position);

                    }
            }
            return true;
        }
    }

    /**
     * 点击右边字母后显示的出的加大字母
     *
     * @author liuyinjun
     * @date 2015-3-16
     */
    private class LetterSelectedView extends View {

        private Paint mPaint;
        /**
         * 选中的字母
         */
        private char mLetter = 'A';

        /**
         * 绘制字母的Y轴坐标
         */
        private float mY;

        public LetterSelectedView(Context context) {
            this(context, null);

        }

        public LetterSelectedView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }

        public LetterSelectedView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init();
        }

        private void init() {
            mPaint = new Paint();
            mPaint.setColor(Color.parseColor("#ff55bb22"));
            mPaint.setTypeface(Typeface.DEFAULT_BOLD);
            mPaint.setTextSize(35);
            mPaint.setAntiAlias(true);
            mPaint.setTextAlign(Paint.Align.CENTER);

        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawText(String.valueOf(mLetter), getMeasuredWidth() / (float) 2, mY, mPaint);
        }

        public void setSelectedLetter(char letter) {
            this.mLetter = letter;
            this.invalidate();//刷新控件
        }


        public void setViewY(float y) {
            this.mY = y;
        }

    }

}

可以看到,该类继承自ListView,自然具有ListView的功能,又重写了父类的方法,增加了按照首字母进行排序的功能。这样一来,使用该自定义类就可自动完成按照首字母的排序要求。

在此基础上,写出的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="fill_parent"
    android:background="#fffafafa"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/white">

        <ImageButton
            android:id="@+id/back_btn"
            android:layout_width="?attr/actionBarSize"
            android:layout_height="?attr/actionBarSize"
            android:layout_alignParentLeft="true"
            android:onClick="FriendBack"
            android:background="@drawable/toolbar_back_bg"
            android:src="?attr/homeAsUpIndicator" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="好友"
            android:textColor="@color/black"
            android:textSize="19sp" />

        <Button
            android:id="@+id/complete_btn"
            android:layout_width="?attr/actionBarSize"
            android:layout_height="?attr/actionBarSize"
            android:layout_alignParentRight="true"
            android:text="完成"
            android:textSize="15sp"
            android:textColor="@color/login_button_default_blue"
            android:background="@drawable/toolbar_back_bg"
            android:src="?attr/homeAsUpIndicator" />
    </RelativeLayout>

    <com.example.sdu.myflag.widget.LetterFilterListView
        android:id="@+id/letterView"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:focusable="true"
        android:focusableInTouchMode="true">

        <ListView
            android:id="@+id/listView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_gravity="center"
            android:cacheColorHint="#00000000"
            android:divider="@null"/>
    </com.example.sdu.myflag.widget.LetterFilterListView>

</LinearLayout>

二、内部处理逻辑代码编写


在之前的详细设计中,已经完成了该功能的详细设计,UML活动图如下所示



根据详细设计,定义了类FriendActivity,具体代码如下所示:

package com.example.sdu.myflag.activity;

import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

import com.example.sdu.myflag.R;
import com.example.sdu.myflag.adapter.FriendListAdapter;
import com.example.sdu.myflag.base.BaseActivity;
import com.example.sdu.myflag.base.BaseApplication;
import com.example.sdu.myflag.bean.FriendBean;
import com.example.sdu.myflag.util.CharacterParser;
import com.example.sdu.myflag.util.NetUtil;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import okhttp3.Response;

/**
 * 好友列表界面
 */
public class FriendActivity extends BaseActivity {

    private ListView listView;
    private FriendListAdapter friendListAdapter;
    int code;
    Button complete;

    @Override
    public int getLayoutId() {
        return R.layout.activity_friend;
    }

    @Override
    public void afterCreate(Bundle savedInstanceState) {
        listView = (ListView) findViewById(R.id.listView);
        code = getIntent().getIntExtra("code", 0);
        complete = (Button) findViewById(R.id.complete_btn);
        complete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.putExtra("selected", friendListAdapter.getSelected());
                setResult(1, intent);
                FriendActivity.this.finish();
            }
        });
        if (code == 0)
            complete.setVisibility(View.GONE);

        getData();
    }

    private void getData() {
        SharedPreferences sp = BaseApplication.getInstance().getSharedPreferences("User", MODE_PRIVATE);
        String id = sp.getString("uid", "");
        ArrayList<NetUtil.Param> params = new ArrayList<>();
        params.add(new NetUtil.Param("id", id));
        try {
            NetUtil.getResult(NetUtil.getFriendListUrl, params, new FriendListCallBack());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void FriendBack(View view) {
        this.finish();
    }

    class FriendListCallBack implements NetUtil.CallBackForResult {

        @Override
        public void onFailure(IOException e) {
            FriendActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(FriendActivity.this, "获取好友列表失败", Toast.LENGTH_SHORT).show();
                }
            });
        }

        @Override
        public void onSuccess(final Response response) {
            if (response.isSuccessful()) {
                try {
                    final String res = response.body().string();
                    FriendActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            JSONArray jsonArray = null;
                            try {
                                JSONObject friend = new JSONObject(res);
                                jsonArray = friend.getJSONArray("friend");

                                ArrayList<FriendBean> list = new ArrayList<>();
                                CharacterParser characterParser = new CharacterParser();
                                for (int i = 0; i < jsonArray.length(); i++) {
                                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                                    String nickname = jsonObject.optString("nickname");
                                    String remark = jsonObject.optString("remark");
                                    String uid = jsonObject.optString("uid");
                                    int iconId = jsonObject.optInt("photo");

                                    String pinYin = characterParser.getSelling(nickname);
                                    String sortString = pinYin.substring(0, 1).toUpperCase();
                                    String firstLetter = "";
                                    if (sortString.matches("[A-Z]")) {
                                        firstLetter = sortString.toUpperCase();
                                    } else {
                                        firstLetter = "#";
                                    }
                                    list.add(new FriendBean(uid, nickname, firstLetter, remark, iconId));
                                }
                                Collections.sort(list);

                                friendListAdapter = new FriendListAdapter(FriendActivity.this, list, code);
                                listView.setAdapter(friendListAdapter);

                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

三、总结

总体来说,这两天的还是不错的,虽然只实现了一个功能,但毕竟对ListView组件进行了重写,还是有一定的工作量的。好友也算一个比较复杂的部分,解决了好友功能,相信之后的工作会更加顺利。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值