android学习 自定义view(组合控件)
项目地址:https://github.com/afei1223/androidStudy
做到后面感觉自己也做了不少东西了,每次到用的时候还是重新造轮子。于是这里准备写一个库专门用来当工具类。
顺便说一下今天的主题吧,Android提供了不少的控件用于使用,但是有些控件用起来不是很顺心。而且有时候写布局的时候越写越多。这个时候可以自己自定义view来解决这个问题。当然,真要全自定义view那挺复杂的,今天记录一下简单的,把所有控件组合起来。
Android有个控件是底部导航栏,但是这东西真的不好用,加了一堆莫名其妙的动画。我到现在还不知道他的点击波纹动画怎么关,所以定个目标下次做一个底部导航栏的。这次稍微简单点,主要是对组合控件的操作和理解。
要定一个组合控件,首先就要先有一个布局。
在layout下创建一个xml文件,然后我在里面加了一个textview,下图中的button之后会移除。
<merge xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <Space android:layout_width="10dp" android:layout_height="match_parent"/> <TextView android:id="@+id/toolbar_title" android:gravity="center_vertical" android:text="标题" android:layout_width="90dp" android:layout_height="match_parent"/> <LinearLayout android:id="@+id/lineraLayout_button_list" android:gravity="right|center" android:layout_marginRight="10dp" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <Button android:id="@+id/toolbar_button_left" android:text="" android:layout_width="30dp" android:layout_height="30dp"/> <Space android:layout_width="10dp" android:layout_height="match_parent"/> <Button android:id="@+id/toolbar_button_right" android:layout_width="30dp" android:layout_height="30dp"/> </LinearLayout> </merge>
如上述代码所述,这个布局的左边是一个textview,右边是一个linearlayout。我想要做的这个控件是一个头部导航栏,那么textview是标题,然后在linaerlayout可以随意添加别的控件,比如按钮。
然后创建一个继承Linearlayout的class。代码如下
public class NavToolBar extends LinearLayout { private String TAG = this.getClass().getSimpleName(); private TextView titleLable; private Context context; public NavToolBar(final Context context, @Nullable AttributeSet attrs) { super(context, attrs); this.context = context; //设置布局 LayoutInflater.from(context).inflate(R.layout.toolbar_layout,this,true); titleLable = findViewById(R.id.toolbar_title); //根据xml中的参数选择如何显示组件 TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.ToolbarLayout); if(attributes != null){ // boolean leftButtonVisible = attributes.getBoolean(R.styleable.ToolbarLayout_haveLeftButton, true); // if (leftButtonVisible) { // buttonLeft.setVisibility(View.VISIBLE); // } else { // buttonLeft.setVisibility(View.INVISIBLE); // } // boolean rightButtonVisible = attributes.getBoolean(R.styleable.ToolbarLayout_haveRightButton, true); // if (rightButtonVisible) { // buttonRight.setVisibility(View.VISIBLE); // } else { // buttonRight.setVisibility(View.INVISIBLE); // } } } //返回textview public TextView getTitleLable(){ return titleLable; } //添加按钮 public Button addButton(int dp, String text){ final Button button = new Button(context); final int px = DPtoPX.dip2px(context,dp); button.setLayoutParams(new LinearLayout.LayoutParams(px,px)); button.setMinimumHeight(0); button.setMinimumWidth(0); button.setText(text); // button.setBackground(R.drawable.ic_more); // button.setBackgroundResource(R.drawable.ic_more); button.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { Toast.makeText(context,"!"+"我是新来的,不要欺负我哦!",Toast.LENGTH_LONG).show(); } }); LinearLayout linearLayout = findViewById(R.id.lineraLayout_button_list); linearLayout.addView(button); return button; } //删除按钮 public void delButton(Button button){ LinearLayout linearLayout = findViewById(R.id.lineraLayout_button_list); linearLayout.removeView(button); } }
关键地方都有注释。这样子一个简单的组合控件就完成了。开放两个接口出去,一个动态添加按钮,一个删除按钮。也满足了我的需求。
下面是怎么用。
final NavToolBar navToolBar = findViewById(R.id.nav_tool_bar); TextView textView = navToolBar.getTitleLable(); textView.setText("导航栏"); final Button button = findViewById(R.id.wheel_add_button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { button1223 = navToolBar.addButton(60,"bt"+buttons.size()); buttons.add(button1223); } }); Button button1 = findViewById(R.id.wheel_remove_button); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(buttons.size()>1){ navToolBar.delButton(buttons.get(1)); buttons.remove(1); } } });
这边提一下增加按钮的时候,我给了一个参数用于设定按钮大小,因为他这里只能用px的,为了适配,所以转换了一下。
组合控件的入门基本上到这里了。然后下面给他小小的升级一下。
我们使用别的控件时,可以直接在xml里给他设置属性,什么text值啊什么,这种如果在代码里去设置就很痛苦。那我们能不能给自己设置一些属性呢。当然是可以的。
首先在values下创建attrs.xml。
在其中添加
<declare-styleable name="ToolbarLayout"> <attr name="titleLabel" format="string"/> <attr name="haveLeftButton" format="boolean"/> <attr name="haveRightButton" format="boolean"/> <attr name="buttonLeftBackground" format="reference"/> <attr name="buttonrightBackground" format="reference"/> </declare-styleable>
这些是属性名字,以及他的类型,比如titleLabel作为标题肯定要是String的吧。具体需要什么属性,自己要用到的时候可以去查一下。
然后添加了这些后需要去绑定到我们的组件中,可以看到之前有一句 TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.ToolbarLayout); 这句就是为了绑定属性,然后他后面的代码其实是用来获取设定xml的属性值来做处理。代码如下
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.ToolbarLayout);
if(attributes != null){ String title = attributes.getString(R.styleable.ToolbarLayout_titleLabel); titleLable.setText(title); }
注意这个ToolbarLayout_titleLabel,前一个表示刚刚设置的name,后一个表示他的属性。组合在一起才可以找到这个属性,然后把这个属性设置到textview上。就可以完成xml中的属性设置了。
组合控件基本上就到这里了,这里多说几句,本来这是一个很简单的东西,无奈官方文档写的不详细,寥寥数笔带过。百度中的教程又少,动不动就是理论,扯一堆,看了半天不知所云。所以这边出一下教程记录一下。如果对自定义view有深入兴趣的,包括绘图什么的,可以看官方文档。https://developer.android.google.cn/guide/topics/ui/custom-components
再多提一下,之前Android学习是记录序号的,但是这里的东西我都是想到一块就写一块,顺着循序反而会误导,而且也有发布时间,所以之后的android学习就不标号了。