可換行的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



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