用户中心项目总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Alen_Sun/article/details/80439609
  • 注册页+忘记密码页
    流程:输入手机号→发送验证码→输入验证码→下一步→输入密码→完成
    异常处理:手机号格式错误,手机号已注册,发送验证码失败,发送验证码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.

Constant Value Description
afterDescendants 1 The ViewGroup will get focus only if none of its descendants want it.
beforeDescendants 0 The ViewGroup will get focus before any of its descendants.
blocksDescendants 2 The 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的使用

阅读更多
换一批

没有更多推荐了,返回首页