团队项目——第一阶段冲刺1

一、前言

昨天 ————————
今天

1、环境搭建

2、明确任务详情

3、考虑设计思路

4、爱好界面设计

遇到的问题 标签排列不规整的问题

二、分析爱好选择功能

1.多种标签有序排列。0.7h

2.点击标签后有回馈。1.2h

3.传递标签内容。(暂未实现)

3.添加有限标签数(目前暂定最多添加5个标签)。0.5h

三、冲刺成果

设计思路

1.使用FlowLayout流式标签进行布局,使标签排列较为整洁

2.回馈采用点击添加后在上方显示的方法(虽然显得麻烦但比较直观)

3.重复添加标签或超出可添加个数使用 Toast 弹框提示

4.添加自定义标签,用户可按照自己的想法添加。添加采用 Dialog 弹框进行添加。

5.根据上述分析,添加依赖

dependencies {

    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation 'com.hyman:flowlayout-lib:1.1.2'

}

效果展示

添加标签示例                                                               

 

 重复添加提示,选择超出提示

        

自定义弹框添加

代码展示

1.Dialog 弹窗设计

    <style name="dialogstyle">
        <!--设置dialog的背景-->
        <item name="android:windowBackground">@android:color/transparent</item>
        <!--设置Dialog的windowFrame框为无-->
        <item name="android:windowFrame">@null</item>
        <!--设置无标题-->
        <item name="android:windowNoTitle">true</item>
        <!--是否浮现在activity之上-->
        <item name="android:windowIsFloating">true</item>
        <!--是否半透明-->
        <item name="android:windowIsTranslucent">true</item>
        <!--设置窗口内容不覆盖-->
        <item name="android:windowContentOverlay">@null</item>
        <!--设置动画,在这里使用让它继承系统的Animation.Dialog-->
        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
        <!--背景是否模糊显示-->
        <item name="android:backgroundDimEnabled">true</item>
    </style>
弹框对话

别忘了在AndroidManifest中添加

<activity
    android:name=".AddTagActivity"
    android:theme="@style/dialogstyle" />

2.流式标签适配器

public class FlowLayoutAdapter extends BaseAdapter {
    private Context mContext;
    private List<String> mList;

    FlowLayoutAdapter(Context context, List<String> list) {
        mContext = context;
        mList = list;
    }

    @Override
    public int getCount() {
        return mList.size();
    }

    @Override
    public String getItem(int position) {
        return mList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @SuppressLint("InflateParams")
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(
                    R.layout.item_tag, null);
            holder = new ViewHolder();
            holder.mBtnTag = convertView.findViewById(R.id.btn_tag);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.mBtnTag.setText(getItem(position));
        return convertView;
    }

    static class ViewHolder {
        Button mBtnTag;
    }
}
View Code

3.标签点击事件(包括刷新数据和回传数据)

public class MainActivity extends Activity {
    private TextView tv_remind;

    private FlowLayout tcy_my_label, tcy_hot_label;
    private FlowLayoutAdapter mMyLabelAdapter;
    private List<String> MyLabelLists, HotLabelLists;

    private static int TAG_REQUESTCODE = 0x101;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initData();
    }

    private void initView() {
        tv_remind = findViewById(R.id.tv_remind);
        tcy_my_label = findViewById(R.id.tcy_my_label);
        tcy_hot_label = findViewById(R.id.tcy_hot_label);
    }

    private void initData() {
        String[] date = getResources().getStringArray(R.array.tags);
        HotLabelLists = new ArrayList<>();
        Collections.addAll(HotLabelLists, date);
        FlowLayoutAdapter mHotLabelAdapter = new FlowLayoutAdapter(this, HotLabelLists);
        tcy_hot_label.setAdapter(mHotLabelAdapter);
        tcy_hot_label.setItemClickListener(new TagCloudLayoutItemOnClick(1));

        MyLabelLists = new ArrayList<>();
        mMyLabelAdapter = new FlowLayoutAdapter(this, MyLabelLists);
        tcy_my_label.setAdapter(mMyLabelAdapter);
        tcy_my_label.setItemClickListener(new TagCloudLayoutItemOnClick(0));

        String labels = String.valueOf(getIntent().getStringExtra("labels"));
        if (!TextUtils.isEmpty(labels) && labels.length() > 0
                && !labels.equals("null")) {
            String[] temp = labels.split(",");
            Collections.addAll(MyLabelLists, temp);
            ChangeMyLabels();
        }

    }


    //刷新我的标签数据
    private void ChangeMyLabels() {
        tv_remind.setVisibility(MyLabelLists.size() > 0 ? View.GONE
                : View.VISIBLE);
        tcy_my_label.setVisibility(MyLabelLists.size() > 0 ? View.VISIBLE
                : View.GONE);
        mMyLabelAdapter.notifyDataSetChanged();
    }


    //标签的点击事件
    class TagCloudLayoutItemOnClick implements FlowLayout.TagItemClickListener {
        int index;

        TagCloudLayoutItemOnClick(int index) {
            this.index = index;
        }

        @Override
        public void itemClick(int position) {
            switch (index) {
                case 0:
                    MyLabelLists.remove(MyLabelLists.get(position));
                    ChangeMyLabels();
                    break;
                case 1:
                    if (MyLabelLists.size() < 5) {
                        if (HotLabelLists.get(position).equals("自定义")) {
                            startActivityForResult(
                                    new Intent(MainActivity.this,
                                            AddTagActivity.class),
                                    TAG_REQUESTCODE);
                        } else {
                            Boolean isExits = isExist(MyLabelLists,
                                    HotLabelLists.get(position));
                            if (isExits) {
                                Toast.makeText(MainActivity.this, "此标签已经添加啦", Toast.LENGTH_LONG).show();
                                return;
                            }
                            MyLabelLists.add(HotLabelLists.get(position));
                            ChangeMyLabels();
                        }
                    } else {
                        Toast.makeText(MainActivity.this, "最多只能添加5个标签", Toast.LENGTH_LONG).show();
                    }
                    break;
                default:
                    break;
            }
        }
    }


    //将数组里面的字符串遍历一遍,看是否存在相同标签
    public static Boolean isExist(List<String> str, String compareStr) {
        boolean isExist = false;//默认沒有相同标签
        for (int i = 0; i < str.size(); i++) {
            if (compareStr.equals(str.get(i))) {
                isExist = true;
            }
        }
        return isExist;
    }


    //回传数据
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (TAG_REQUESTCODE == requestCode) {
            if (resultCode == AddTagActivity.TAG_RESULTCODE) {
                String label = data.getStringExtra("tags");
                MyLabelLists.add(label);
                ChangeMyLabels();
            }
        }
    }
}
View Code

4.标签添加(点击后的回馈)

public class AddTagActivity extends Activity implements View.OnClickListener {

    private EditText mEtLabel;
    public final static int TAG_RESULTCODE = 0x102;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_tag);
        initView();
        initData();
    }

    private void initData() {
        //根据输入框输入值的改变提示最大允许输入的个数
        mEtLabel.addTextChangedListener(new TextWatcher_Enum());
    }

    private void initView() {
        mEtLabel = findViewById(R.id.et_label);
        Button mBtnSure = findViewById(R.id.btn_sure);

        mBtnSure.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_sure) {
            String label = mEtLabel.getText().toString();
            if (TextUtils.isEmpty(label)) {
                Toast.makeText(AddTagActivity.this, "自定义标签不应为空", Toast.LENGTH_LONG).show();
                return;
            }
            Intent intent = getIntent();
            intent.putExtra("tags", label);
            setResult(TAG_RESULTCODE, intent);
            finish();
        }
    }


    //根据输入框输入值的长度超过8个字符的时候,弹出输入的标签应控制在8个字
    class TextWatcher_Enum 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) {
            int lenght = mEtLabel.getText().toString().trim().length();
            if (lenght > 8) {
                Toast.makeText(AddTagActivity.this, "输入的标签应控制在8个字", Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    }
}
View Code

5.定义标签样式

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--每个item纵向间距-->
    <attr name="verticalSpacing" format="dimension" />
    <!-- 每个item横向间距-->
    <attr name="horizontalSpacing" format="dimension" />

    <declare-styleable name="FlowLayout">
        <attr name="verticalSpacing" />
        <attr name="horizontalSpacing" />
    </declare-styleable>

</resources>

调用上面xml代码来规定各个标签之间距离

public class FlowLayout extends ViewGroup {

    //每个item纵向间距
    private int mVerticalSpacing;
    //每个item横向间距
    private int mHorizontalSpacing;
    private BaseAdapter mAdapter;
    private TagItemClickListener mListener;
    private DataChangeObserver mObserver;

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

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

    public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        //获取自定义样式属性
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.FlowLayout, defStyle, 0);
        for (int i = 0; i < a.getIndexCount(); i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.FlowLayout_verticalSpacing:
                    mVerticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_verticalSpacing, 5);
                    break;
                case R.styleable.FlowLayout_horizontalSpacing:
                    mHorizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_horizontalSpacing, 10);
                    break;
            }
        }
        a.recycle();
    }


    //负责设置子控件的测量模式和大小 根据所有子控件设置自己的宽和高
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        // 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式
        int heighMode = MeasureSpec.getMode(heightMeasureSpec);
        int heighSize = MeasureSpec.getSize(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        //
        int height = 0;
        // 每一行的高度,累加至height
        int lineHeight = 0;
        // 在warp_content情况下,记录当前childView的左边的一个位置
        int childLeft = getPaddingLeft();
        // 在warp_content情况下,记录当前childView的上边的一个位置
        int childTop = getPaddingTop();
        // getChildCount得到子view的数目,遍历循环出每个子View
        for (int i = 0; i < getChildCount(); i++) {
            //拿到index上的子view
            View childView = getChildAt(i);
            // 测量每一个child的宽和高
            measureChild(childView, widthMeasureSpec, heightMeasureSpec);
            //当前子空间实际占据的高度
            int childHeight = childView.getMeasuredHeight();
            //当前子空间实际占据的宽度
            int childWidth = childView.getMeasuredWidth();
            lineHeight = Math.max(childHeight, lineHeight);// 取最大值
            //如果加入当前childView,超出最大宽度,则将目前最大宽度给width,类加height 然后开启新行
            if (childWidth + childLeft + getPaddingRight() > widthSize) {
                childLeft = getPaddingLeft();// 重新开启新行,开始记录childLeft
                childTop += mVerticalSpacing + childHeight;// 叠加当前的高度
                lineHeight = childHeight;// 开启记录下一行的高度
            } else {
                //否则累加当前childView的宽度
                childLeft += childWidth + mHorizontalSpacing;
            }
        }
        height += childTop + lineHeight + getPaddingBottom();
        setMeasuredDimension(widthSize, heighMode == MeasureSpec.EXACTLY ? heighSize : height);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int width = r - l;
        int childLeft = getPaddingLeft();
        int childTop = getPaddingTop();
        int lineHeight = 0;
        //遍历所有childView根据其宽和高,计算子控件应该出现的位置
        for (int i = 0; i < getChildCount(); i++) {
            final View childView = getChildAt(i);
            if (childView.getVisibility() == View.GONE) {
                continue;
            }
            int childWidth = childView.getMeasuredWidth();
            int childHeight = childView.getMeasuredHeight();
            lineHeight = Math.max(childHeight, lineHeight);
            // 如果已经需要换行
            if (childLeft + childWidth + getPaddingRight() > width) {
                childLeft = getPaddingLeft();
                childTop += mVerticalSpacing + lineHeight;
                lineHeight = childHeight;
            }
            childView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
            childLeft += childWidth + mHorizontalSpacing;
        }
    }

    private void drawLayout() {
        if (mAdapter == null || mAdapter.getCount() == 0) {
            return;
        }
        removeAllViews();
        for (int i = 0; i < mAdapter.getCount(); i++) {
            View view = mAdapter.getView(i, null, null);
            final int position = i;
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mListener != null) {
                        mListener.itemClick(position);
                    }
                }
            });
            addView(view);
        }
    }

    public void setAdapter(BaseAdapter adapter) {
        if (mAdapter == null) {
            mAdapter = adapter;
            if (mObserver == null) {
                mObserver = new DataChangeObserver();
                mAdapter.registerDataSetObserver(mObserver);
            }
            drawLayout();
        }
    }

    public void setItemClickListener(TagItemClickListener mListener) {
        this.mListener = mListener;
    }

    public interface TagItemClickListener {
        void itemClick(int position);
    }

    class DataChangeObserver extends DataSetObserver {
        @Override
        public void onChanged() {
            drawLayout();
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
        }
    }
}
自定义标签
原文地址:https://www.cnblogs.com/best-hym/p/12708477.html