用户中心项目总结

  • 注册页+忘记密码页
    流程:输入手机号→发送验证码→输入验证码→下一步→输入密码→完成
    异常处理:手机号格式错误,手机号已注册,发送验证码失败,发送验证码90s后才能再次发送,验证码错误,密码不合法,没有网络等。
    架构使用了MVP模式,并且运用了依赖倒置原则。
    布局用到的特殊属性:

TextView android:drawableLeft

The drawable to be drawn to the left of the text.

TextView android:drawablePadding
使用这2个属性可以在文字前加图片而无需加一个ImageView

The padding between the drawables and the text.

TextView android:includeFontPadding
文字通常没有上标和下标,设成false后的TextView的高度可以更符合标注的要求。

Leave enough room for ascenders and descenders instead of using the font ascent and descent strictly. (Normally true).

ViewGroup android:addStatesFromChildren
下面的说明中就描述了这个属性的作用,可以使包含EditText的外层布局获得焦点等。

Sets whether this ViewGroup’s drawable states also include its children’s drawable states. This is used, for example, to make a group appear to be focused when its child EditText or button is focused.

  • 我的页+勋章页

1.两个勋章页均使用MVP架构,使用Picasso加载网络图片,使用Gson解析Json数据。

2.使用View.post(Runnable action)方法,可以在页面加载完成之后再做对该View获取焦点等操作。具体原理可以参考【Andorid源码解析】View.post() 到底干了啥

View.post(Runnable action)
Causes the Runnable to be added to the message queue. The runnable will be run on the user interface thread.

3.使用SpannableString实现字符串的富文本效果

strings.xml
<string name="my_medal_overview">您一共获得了 %1$d 个勋章,其中%2$d年获得 %3$d 个,%4$d年获得 %5$d 个</string>
String s = getString(R.string.my_medal_overview, medals.size(), now.get(Calendar.YEAR) - 1, lastYear, now.get(Calendar.YEAR), thisYear);
SpannableString ss = new SpannableString(s);
ss.setSpan(new AbsoluteSizeSpan(48), s.indexOf(' ', start), s.indexOf(' ', s.indexOf(' ', start) + 1), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
myMedalOverviewText.setText(ss);

4.两个勋章页均使用单层RecyclerView。我的勋章页初期考虑使用嵌套RecyclerView,后来根据效果图改为单层RecyclerView
RecyclerView的使用方法:

  • 新建一个类继承RecyclerView.Adapter<T extends RecyclerView.ViewHolder>,重写onCreateViewHolderonBindViewHoldergetItemCount3个方法。

  • onCreateViewHolder中,构造一个RecyclerView.ViewHolder并将子View的布局传给它,然后返回这个ViewHolder

  • onBindViewHolder中,根据position的值对ViewHolder设定数据和样式等。由于ViewHolder会复用,当其重新出现在界面时,会保留复用前的数据,所以每次(即在该函数里)都要对所有数据和样式重新设定。

  • Adapter中实现子View的View.OnFocusChangeListener等,将这些listener传给ViewHolder,可以增加复用并减少实例化。

  • 新建这个Adapter的实例并通过RecyclerView.setAdapter(RecyclerView.Adapter adapter)传给RecyclerView

5.在全部勋章页,采取4列的RecyclerView布局,当焦点在第一行按向上键时,焦点会跑向左边。为解决此问题,对子View设置这个View.OnKeyListener

View.OnKeyListener onKeyListener = new View.OnKeyListener() {
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        int position = (int) v.getTag();
        if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
            if (position < AllMedalActivity.COLUMN_COUNT) {
                return true;
            }
        }
        return false;
    }
};

6.我的页,由于焦点框会盖住角标,因此新建一层FrameLayout,放在content下。一开始这个Layout跟PageUser写在了一块,难以维护。后来根据面向对象的单一职责原则,将该FrameLayout抽取出来,单独成立一个类BadgeFrame。这个可以说是这个项目的一个难点。

ViewGroup contentView = (ViewGroup) view.getRootView().findViewById(android.R.id.content);
contentView.addView(this);

7.布局用到的特殊属性:
ViewGroup android:descendantFocusability

Defines the relationship between the ViewGroup and its descendants when looking for a View to take focus.
Must be one of the following constant values.

ConstantValueDescription
afterDescendants1The ViewGroup will get focus only if none of its descendants want it.
beforeDescendants0The ViewGroup will get focus before any of its descendants.
blocksDescendants2The ViewGroup will block its descendants from receiving focus.

ViewGroup android:clipChildren

Defines whether a child is limited to draw inside of its bounds or not. This is useful with animations that scale the size of the children to more than 100% for instance. In such a case, this property should be set to false to allow the children to draw outside of their bounds. The default value of this property is true.

使用selector,可参考Android中selector的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值