主xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.day_0609.MainActivity"> <com.example.day_0609.TitleView android:id="@+id/titleView_main" android:layout_width="match_parent" android:layout_height="wrap_content" app:left_text="-" app:right_text="+" app:title_text="首页"></com.example.day_0609.TitleView> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/scrollView_main" > <com.example.day_0609.FlowLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/flowLayout_main" > </com.example.day_0609.FlowLayout> </ScrollView> </LinearLayout>
attrs<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TopBar">
<attr name="title_text" format="string"></attr>
<attr name="title_text_size" format="dimension"></attr>
<attr name="title_text_color" format="color"></attr>
<attr name="title_bg_color" format="color"></attr>
<attr name="left_btn_text" format="string"></attr>
<attr name="left_btn_text_size" format="dimension"></attr>
<attr name="left_btn_text_color" format="color"></attr>
<attr name="left_btn_bg_color" format="reference"></attr>
<attr name="right_btn_text" format="string"></attr>
<attr name="right_btn_text_size" format="dimension"></attr>
<attr name="right_btn_text_color" format="color"></attr>
<attr name="right_btn_bg_color" format="reference"></attr>
</declare-styleable>
</resources>
子布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="60dp" android:background="@color/colorPrimary" > <Button android:id="@+id/btn_left" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:textSize="20dp" android:background="@color/colorAccent" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:id="@+id/tv_title" android:layout_weight="1" android:layout_gravity="center" android:gravity="center" android:textSize="24dp" /> <Button android:id="@+id/btn_right" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:textSize="20dp" android:background="@color/colorAccent" /> </LinearLayout>
主 activity
public class MainActivity extends AppCompatActivity { private TitleView titleView; private FlowLayout flowLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化页面 initViews(); } private void initViews() { titleView = findViewById(R.id.titleView_main); flowLayout = findViewById(R.id.flowLayout_main); //设置监听 titleView.setButtonOnClickListener(new TitleView.ButtonOnClickListener() { @Override public void leftOnClick() { //左按钮点击减少view flowLayout.removeViewAt(0); } @Override public void titleOnCLick() { //标题点击清除view flowLayout.removeAllViews(); } @Override public void rightOnClick() { //右按钮点击添加view Button button = new Button(getApplicationContext()); button.setText("杨运泽 宇宙无敌"); button.setTextColor(Color.RED); //FlowLayout 继承的是ViewGroup,所以这里用ViewGroup ViewGroup.LayoutParams params = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT ); //设置宽度为屏幕的一半 params.width = getWindowManager().getDefaultDisplay().getWidth()/2; //设置高度为屏幕的1/5 params.height = getWindowManager().getDefaultDisplay().getHeight()/25; //添加布局 flowLayout.addView(button,params); } }); } }
FlowLayout
public class FlowLayout extends ViewGroup { public FlowLayout(Context context) { super(context); } public FlowLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //测量所有孩子的宽高 measureChildren(widthMeasureSpec, heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int heigghtMode = MeasureSpec.getMode(heightMeasureSpec); int width = 0; int height = 0; int lineWidth = 0; int lineHeight = 0; int totalHeight = 0; View childView; int childWidth = 0; int childHeight = 0; //遍历 for (int i = 0; i < getChildCount(); i++) { //获得孩子组件 childView = getChildAt(i); //获得孩子的宽高 childWidth = childView.getMeasuredWidth(); width = 2 * childWidth; childHeight = childView.getMeasuredHeight(); //如果孩子宽太大 if (childWidth > widthSize) { throw new IllegalArgumentException("子控件的宽度不能大于父控件的宽度"); } //判断在左还是在右 if (i % 2 == 0) { //累积的高添加 totalHeight += lineHeight; lineHeight = childHeight; lineWidth = childWidth; } else { //累积的高添加 totalHeight += lineHeight; //行宽累加 lineWidth += childWidth; lineHeight = childHeight; } //如果是最后一个 if (i == getChildCount() - 1) { totalHeight += lineHeight; height = totalHeight; } } //模式的判断 width = widthMode == MeasureSpec.EXACTLY ? widthSize : width; height = heigghtMode == MeasureSpec.EXACTLY ? heightSize : height; //设置测量的宽高 setMeasuredDimension(width,height); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int lineWidth = 0; int lineHeight = 0; int totalHeight = 0; View childView; int childWidth = 0; int childHeight = 0; //遍历 for (int i = 0; i < getChildCount(); i++) { //获得孩子组件 childView = getChildAt(i); //获得孩子的宽高 childWidth = childView.getMeasuredWidth(); childHeight = childView.getMeasuredHeight(); //判断在左还是在右 if (i % 2 == 0) { totalHeight += lineHeight; //模为0的都是第一个,所以行宽赋0 lineWidth = 0; childViewLayout(childView,lineWidth,totalHeight,lineWidth+childWidth,totalHeight+childHeight); lineHeight = childHeight; lineWidth = childWidth; } else { totalHeight += lineHeight; //模为1的都是第二个 所以行宽为累加 childViewLayout(childView,lineWidth,totalHeight,lineWidth+childWidth,totalHeight+childHeight); lineWidth += childWidth; lineHeight = childHeight; } } } public void childViewLayout(View childView,int l,int t,int r,int b){ childView.layout(l,t,r,b); } }
按钮
public class TitleView extends LinearLayout implements View.OnClickListener { private ButtonOnClickListener buttonOnClickListener; public TitleView(Context context) { super(context); } public TitleView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public TitleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //加载属性 TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TitleView, 0, 0); String titleText = typedArray.getString(R.styleable.TitleView_title_text); String leftText = typedArray.getString(R.styleable.TitleView_left_text); String rightText = typedArray.getString(R.styleable.TitleView_right_text); //加载布局 View inflate = inflate(context, R.layout.title_view_layout, this); TextView titleTv = inflate.findViewById(R.id.tv_title); Button leftBtn = inflate.findViewById(R.id.btn_left); Button rightBtn = inflate.findViewById(R.id.btn_right); //设置属性 titleTv.setText(titleText); leftBtn.setText(leftText); rightBtn.setText(rightText); //设置点击事件 leftBtn.setOnClickListener(this); titleTv.setOnClickListener(this); rightBtn.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_left: buttonOnClickListener.leftOnClick(); break; case R.id.tv_title: buttonOnClickListener.titleOnCLick(); break; case R.id.btn_right: buttonOnClickListener.rightOnClick(); break; default: break; } } //接口回调 public interface ButtonOnClickListener { void leftOnClick(); void titleOnCLick(); void rightOnClick(); } //外部访问的方法 public void setButtonOnClickListener(ButtonOnClickListener buttonOnClickListener) { this.buttonOnClickListener = buttonOnClickListener; } }