自定義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