zoukankan      html  css  js  c++  java
  • 团队项目——第一阶段冲刺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();
            }
        }
    }
    自定义标签
  • 相关阅读:
    数据结构与算法分析
    案例分析作业
    实验六——循环结构程序练习总结
    实验五——循环结构学习总结
    实验四——多分支结构及本章总结
    实验三——for 语句及分支结构else-if
    第二次作业及总结——数据类型和运算符
    2-c语言作业
    自然博物馆参观
    2019-2020-1学期 20192409《网络空间安全专业导论》第四周学习总结
  • 原文地址:https://www.cnblogs.com/best-hym/p/12708477.html
Copyright © 2011-2022 走看看