Android编辑昵称、个性签名

版权声明:个人原创,欢迎转载。 https://blog.csdn.net/chuyangchangxi/article/details/86749821

一、目标

在这里插入图片描述

二、下载地址

神马笔记最新版本下载:【神马笔记 版本1.5.0——笔名功能.apk

三、功能设计

  • 标题栏组成
  1. 标题——显示当前编辑的目标
  2. 返回按钮——取消编辑内容
  3. 完成按钮——只有输入内容发生改变时可用,完成编辑内容
  • 内容界面组成
  1. 文本——编辑框默认内容
  2. 提示——编辑框的提示文本
  3. 名称——显示在编辑框左上角,简短说明
  4. 解释——显示在编辑框左下角,进一步说明
  • 输入文本限定
  1. 限定文本最大长度——默认不限定
  2. 限定文本最小行数——默认为1行
  3. 限定文本最大行数——默认不限定

四、准备工作

编辑昵称、个性签名使用EditText即可完成,毫无技术难度。

常见的界面实现方式有2种——局部和全屏。
在这里插入图片描述

  • 左侧——聊天宝以弹出局部对话框的方式编辑名称

  • 右侧——微信以全屏的方式编辑名称

界面实现是选择局部,还是全屏?这是个有趣的问题。

从实现方式上考虑,二者都没有什么技术难度,开发时间也相差无几。

从用户体验上考虑,也是萝卜青菜各有所爱,分不出优劣。

最后选择的实现方式——全屏

理由——切换输入法时,局部对话框会上下移动。

实在不喜欢对话框发生移动,因此最终选择全屏方式。

五、组合起来

1. 布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              tools:context=".preference.ComposeTextFragment">

    <app.haiyunshan.whatsnote.widget.SearchTitleBar
            android:id="@+id/title_bar"
            android:layout_width="match_parent"
            app:searchVisible="false"
            android:layout_height="wrap_content"
            android:background="@drawable/shape_preference_top_bar_bg">

    </app.haiyunshan.whatsnote.widget.SearchTitleBar>

    <androidx.core.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fillViewport="true"
            android:overScrollMode="never">

        <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:paddingTop="?listPreferredItemPaddingLeft"
                android:paddingBottom="?listPreferredItemPaddingRight">

            <include
                    android:id="@+id/tv_name"
                    layout="@layout/layout_setting_title_list_item"
                    android:layout_marginBottom="4dp"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"/>

            <EditText
                    android:id="@+id/edit_text"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingTop="10dp"
                    android:paddingBottom="10dp"
                    android:gravity="top|left"
                    android:paddingLeft="?listPreferredItemPaddingLeft"
                    android:paddingRight="?listPreferredItemPaddingRight"
                    android:background="@drawable/shape_compose_text_bg">
                <requestFocus/>
            </EditText>

            <include
                    android:id="@+id/tv_explain"
                    layout="@layout/layout_setting_explain_list_item"
                    android:layout_marginTop="4dp"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"/>

        </LinearLayout>
    </androidx.core.widget.NestedScrollView>
</LinearLayout>

2. Fragment

package app.haiyunshan.whatsnote.preference;


import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputFilter;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import app.haiyunshan.whatsnote.R;
import app.haiyunshan.whatsnote.base.MenuItemClickListener;
import app.haiyunshan.whatsnote.widget.SearchTitleBar;
import club.andnext.helper.ClearAssistMenuHelper;
import club.andnext.ucrop.BuildConfig;

import java.util.Arrays;

/**
 * A simple {@link Fragment} subclass.
 */
public class ComposeTextFragment extends Fragment {

    private static final String EXTRA_PREFIX = BuildConfig.APPLICATION_ID;

    SearchTitleBar titleBar;

    TextView nameView;
    EditText editText;
    TextView explainView;

    String text;
    MenuItem doneMenuItem;

    public ComposeTextFragment() {

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_compose_text, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        {
            this.titleBar = view.findViewById(R.id.title_bar);

            Toolbar toolbar = titleBar.getToolbar();
            toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp);
            toolbar.setNavigationOnClickListener(this::onNavigationClick);

            toolbar.inflateMenu(R.menu.menu_compose);
            toolbar.setOnMenuItemClickListener(new MenuItemClickListener().put(R.id.menu_done, this::onDoneClick));

            this.doneMenuItem = toolbar.getMenu().findItem(R.id.menu_done);
            doneMenuItem.setEnabled(false);
        }

        {
            this.nameView = view.findViewById(R.id.tv_name);
            this.editText = view.findViewById(R.id.edit_text);
            this.explainView = view.findViewById(R.id.tv_explain);
        }

        {
            ClearAssistMenuHelper.attach(editText);

            this.editText.addTextChangedListener(new ComposeTextListener());
        }
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        Bundle args = this.getArguments();

        {
            CharSequence cs = args.getCharSequence(Builder.EXTRA_TEXT);

            this.text = (TextUtils.isEmpty(cs))? "": cs.toString();
        }

        {
            CharSequence title = args.getCharSequence(Builder.EXTRA_TITLE);
            titleBar.setTitle(title);
        }

        {
            int maxLength = args.getInt(Options.EXTRA_MAX_LENGTH, -1);
            if (maxLength > 0) {
                InputFilter[] filters = editText.getFilters();

                {
                    filters = Arrays.copyOf(filters, filters.length + 1);
                    filters[filters.length - 1] = new InputFilter.LengthFilter(maxLength);
                }

                editText.setFilters(filters);
            }

            int minLines = args.getInt(Options.EXTRA_MIN_LINES, -1);
            if (minLines > 0) {
                editText.setMinLines(minLines);
            }

            int maxLines = args.getInt(Options.EXTRA_MAX_LINES, -1);
            if (maxLines > 0) {
                editText.setMaxLines(maxLines);
            }

            if (minLines <= 1 && maxLines <= 1) {
                editText.setSingleLine(true);
            }

        }

        {
            CharSequence hint = args.getCharSequence(Options.EXTRA_HINT);
            editText.setHint(hint);
        }

        {
            CharSequence text = args.getCharSequence(Options.EXTRA_NAME);
            nameView.setVisibility(TextUtils.isEmpty(text)? View.GONE: View.VISIBLE);
            nameView.setText(text);
        }

        {
            CharSequence text = args.getCharSequence(Options.EXTRA_EXPLAIN);
            explainView.setVisibility(TextUtils.isEmpty(text)? View.GONE: View.VISIBLE);
            explainView.setText(text);
        }

        {
            editText.setText(text);
            editText.setSelection(text.length());
        }

    }

    void onNavigationClick(View view) {
        getActivity().onBackPressed();
    }

    void onDoneClick(MenuItem item) {
        Intent intent = new Intent();
        intent.putExtra(Builder.EXTRA_TEXT, editText.getText().toString());

        getActivity().setResult(Activity.RESULT_OK, intent);
        getActivity().onBackPressed();
    }

    /**
     *
     */
    private class ComposeTextListener implements TextWatcher {

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            boolean equals = (text.equals(s.toString()));
            doneMenuItem.setEnabled(!equals);
        }
    }

    /**
     *
     */
    public static class Builder {

        public static final String EXTRA_TITLE  = EXTRA_PREFIX + ".Title";
        public static final String EXTRA_TEXT   = EXTRA_PREFIX + ".Text";

        protected Intent intent;
        protected Bundle bundle;

        public Builder(@NonNull CharSequence title, @NonNull CharSequence text) {
            this.intent = new Intent();

            this.bundle = new Bundle();
            bundle.putCharSequence(EXTRA_TITLE, title);
            bundle.putCharSequence(EXTRA_TEXT, text);
        }

        public Builder withOptions(@NonNull Options options) {
            bundle.putAll(options.getOptionBundle());

            return this;
        }
    }

    /**
     *
     */
    public static class Options {

        public static final String EXTRA_NAME = EXTRA_PREFIX + ".Name";
        public static final String EXTRA_HINT = EXTRA_PREFIX + ".Hint";
        public static final String EXTRA_EXPLAIN = EXTRA_PREFIX + ".Explain";

        public static final String EXTRA_MAX_LENGTH = EXTRA_PREFIX + ".MaxLength";

        public static final String EXTRA_MIN_LINES = EXTRA_PREFIX + ".MinLines";
        public static final String EXTRA_MAX_LINES = EXTRA_PREFIX + ".MaxLines";

        private final Bundle mOptionBundle;

        public Options() {
            mOptionBundle = new Bundle();
        }

        @NonNull
        public Bundle getOptionBundle() {
            return mOptionBundle;
        }

        public void setName(CharSequence name) {
            mOptionBundle.putCharSequence(EXTRA_NAME, name);
        }

        public void setHint(CharSequence hint) {
            mOptionBundle.putCharSequence(EXTRA_HINT, hint);
        }

        public void setExplain(CharSequence explain) {
            mOptionBundle.putCharSequence(EXTRA_EXPLAIN, explain);
        }

        public void setMaxLength(int length) {
            mOptionBundle.putInt(EXTRA_MAX_LENGTH, length);
        }

        public void setMinLines(int value) {
            mOptionBundle.putInt(EXTRA_MIN_LINES, value);
        }

        public void setMaxLines(int value) {
            mOptionBundle.putInt(EXTRA_MAX_LINES, value);
        }

    }
}

这里借鉴了uCrop的设计方式。

Builder传入必须的2个参数——Title和Text。这2个为必须参数。

Options提供了设置可选参数接口——名称、提示、注解以及最大长度、最小行数、最大行数共6个信息。

六、Finally

~白首相知犹按剑~朱门先达笑弹冠~

猜你喜欢

转载自blog.csdn.net/chuyangchangxi/article/details/86749821