可换行的AutoBreakViewGroup扩展

前段时间一位开发安卓的小伙伴问我一个需求,公司UI妹子给了他一张图,一个加号,一个减号,动态的添加标签,要求流布局的效果实现,考虑到不要重复的造轮子,就在网上找流布局的自定义view,纵里寻她千百度,那view却在http://blog.csdn.net/syusikoku/article/details/52260811处。尴尬

自定义ViewGroup实现换行

于是怀着无比崇拜的心情开始了需求的实现:由于该博客已经写得非常详细,并且知识点也不是很难,直接上代码

布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.bobo.AutoBreakViewGroup
        android:id="@+id/autoBreakViewGroup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"/>
</LinearLayout>
考虑使用封装管理的需求,加号和减号封装view中,代码如下:

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;

/**
 * Created by bobo on 2017/5/8.
 */
public class OperateView extends FrameLayout {
    Context mContext;

    public OperateView(Context context) {
        super(context);
        init(context,null);
    }

    public OperateView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

    public OperateView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }
    private void init(Context context, AttributeSet attrs){
        mContext = context;
        View view = LayoutInflater.from(context).inflate(R.layout.view_content_ope,
                this, true);
    }
}
view_content_ope.xml的代码如下开始的时候不用删除,所以减号隐藏掉:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/tv_add"
        android:layout_width="45dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:background="@drawable/item_bg"
        android:layout_centerInParent="true"
        android:text="+"/>
    <TextView
        android:id="@+id/tv_delete"
        android:visibility="gone"
        android:layout_width="45dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:background="@drawable/item_bg"
        android:layout_centerInParent="true"
        android:text="-"/>
</LinearLayout>
好了,准备工作结束开始代码撸起偷笑首先把操作view加到viewgroup中关键代码如下:

autoBreakViewGroup= (AutoBreakViewGroup) findViewById(R.id.autoBreakViewGroup);
//把加号和减号封装到一个LinearLayout中
OperateView operateView=new OperateView(MainActivity.this);
//找到加号和减号的控件
add= (TextView) operateView.findViewById(R.id.tv_add);
delete= (TextView) operateView.findViewById(R.id.tv_delete);
//刚开始把加号加到viewgroup中去
autoBreakViewGroup.addView(operateView);
//添加事件
initEvent();
为加号和减号注册点击事件如下:

private void initEvent() {
    add.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //点击加号后,先生成一个edittext,在里面进行编辑
            final EditText editText = new EditText(MainActivity.this);
            editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
            editText.setTextColor(Color.BLACK);
            editText.setLayoutParams(new
                    ViewGroup.LayoutParams(300, ViewGroup.LayoutParams.WRAP_CONTENT));
            editText.setBackgroundResource(R.drawable.item_bg);
            editText.setPadding(20, 10, 20, 10);
            //editText.setGravity(Gravity.CENTER);
            //设置软键盘的换行键不换行
            editText.setLines(1);
            editText.setImeOptions(EditorInfo.IME_ACTION_SEND);
            editText.setFocusable(true);
            editText.setFocusableInTouchMode(true);
            editText.requestFocus();
            InputMethodManager inputManager = (InputMethodManager)editText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            inputManager.showSoftInput(editText, 0);
            //把edittext添加到加号之前去
            autoBreakViewGroup.addView(editText, autoBreakViewGroup.getChildCount() - 1);
            editText.setOnKeyListener(new View.OnKeyListener() {
                @Override
                public boolean onKey(View v, int keyCode, KeyEvent event) {
                    if (keyCode == KeyEvent.KEYCODE_ENTER) {
                        // 先隐藏键盘
                        ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE))
                                .hideSoftInputFromWindow(
                                        ZDYIosActivity.this
                                                .getCurrentFocus()
                                                .getWindowToken(),
                                        InputMethodManager.HIDE_NOT_ALWAYS);
                        //进行标签的添加操作,首先先把先前创建的edittext从viewgroup中去掉
                        autoBreakViewGroup.removeViewAt(autoBreakViewGroup.getChildCount() - 2);
                        //标签的生成
                        addView(editText.getText().toString());
                    }
                    return false;
                }
            });

        }
    });
    delete.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //点击减号后的思路
            int count=autoBreakViewGroup.getChildCount()-1;  //因为最后一个是操作的view,不是标签,所以循环取长度-1;目的是不算那个操作的view
            for (int i = 0; i < count; i++) {
                //删除点击标签删除,也可以把点击事件加在你的那个删除图片上面
                ContentView contentView= (ContentView) autoBreakViewGroup.getChildAt(i);
                //封装的一个方法,刚开始删除图片不显示,点击减号后删除图片显示出来
                contentView.showCancel();
                contentView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {

                            autoBreakViewGroup.removeView(v);
                            //如果里面都删除完了把减号隐藏掉
                            if(autoBreakViewGroup.getChildCount()==1){
                                delete.setVisibility(View.GONE);
                            }
                        }
                });

            }
        }
    });
}
因为有删除操作,所以考虑标签也封装成view来实现,也就是上文的ContentView,代码如下:

/**
 * Created by bobo on 2017/5/8.
 */
public class ContentView extends FrameLayout {
    Context mContext;
    TextView textView;
    ImageView imageView;
    public ContentView(Context context) {
        super(context);
        init(context,null);
    }

    public ContentView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

    public ContentView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }
    private void init(Context context, AttributeSet attrs){
        mContext = context;
        View view = LayoutInflater.from(context).inflate(R.layout.view_content,
                this, true);
        textView= (TextView) view.findViewById(R.id.tv_content);
        imageView= (ImageView) findViewById(R.id.iv_cancel);
    }
    public void setContent(String content){
       textView.setText(content);
    }

    public void showCancel(){
        imageView.setVisibility(VISIBLE);
    }
}
布局文件很简单,这就不贴代码了偷笑,删除有点low

操作中addView方法如下

private void addView(String content) {
    //因为有那个右上角的删除要出来,所以先封装一下,有点low可以考虑换一下那个删除键
   ContentView contentView=new ContentView(MainActivity.this);
   contentView.setContent(content);
    autoBreakViewGroup.addView(contentView, autoBreakViewGroup.getChildCount() - 1);
    //当添加了一个标签以后就可以把减号显示出来了
    delete.setVisibility(View.VISIBLE);
}
好了,大功告成!效果如下:





添加标签后的截图:

是不是有点low,呵呵,其实我也是小菜了大笑大笑,接下来问题来了,UI妹子要把这个功能加在页面的中间,最外层嵌套一个ScrollView,大家可以试一下,刚进去的加号不见了,Where's the plus sign?

网上找相关的代码,没有比较方便的方法可以解决这个问题,只能回到大神写的AutoBreakViewGroup中,打log,打断点的找原因,终于功夫不负我这有心人,还真就找到了吐舌头,刚进去加载viewgroup的时候

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    measureChildren(widthMeasureSpec, heightMeasureSpec);
    setMeasuredDimension(widthSize, heightSize);
}
返回的高度为0,所以不会显示大笑,找到原因那就该解决方法了,一种最简单的方法,也是自认为最low的方法

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    measureChildren(widthMeasureSpec, heightMeasureSpec);
     if(height==0){
         //当高度为0时也就是刚进去的时候,给个默认高度50
        setMeasuredDimension(widthSize, 50);
    }else {
         //当有标签后,为了避免刚好一行走完,会把操作view挤出去,往后都比实际的高处50,来装操作view
        setMeasuredDimension(widthSize, height+50);
    }
    setMeasuredDimension(widthSize, heightSize);
}
呵呵,是不是加号出来了,有木有很开心害羞,还有另一种方案比较委婉,没这么暴力,代码如下:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    measureChildren(widthMeasureSpec, heightMeasureSpec);
    int mTotalHeight = 0;
    int mTotalWidth = 0;
    int mTempHeight = 0;
    int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
        View childView = getChildAt(i);
        int measureHeight = childView.getMeasuredHeight();
        int measuredWidth = childView.getMeasuredWidth();
        if(mHorizontalSpacing==0) {
            mHorizontalSpacing = mScreenWidth / ((mScreenWidth / measuredWidth) * (mScreenWidth / measuredWidth));
        }
        mTempHeight = (measureHeight > mTempHeight) ? measureHeight : mTempHeight;
        if ((measuredWidth + mTotalWidth + mHorizontalSpacing) > mScreenWidth) {
            mTotalWidth = 0;
            mTotalHeight += (mTempHeight + mVerticalSpacing);
            mTempHeight = 0;
        }

        childView.layout(mTotalWidth + mHorizontalSpacing, mTotalHeight, measuredWidth + mTotalWidth + mHorizontalSpacing, mTotalHeight + measureHeight);
        mTotalWidth += (measuredWidth + mHorizontalSpacing);
        height = mTotalHeight + measureHeight;
    }
    setMeasuredDimension(widthSize, height);
}
有木有感觉很委婉了,刚进去就测量一次,然后返回,这样刚进去加号也在。第一次写有点紧张,希望大家多多提意见,一起进步哦!

参考博客:http://blog.csdn.net/syusikoku/article/details/52260811



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章