当前位置: 移动技术网 > IT编程>开发语言>Java > 《第一行代码》阅读笔记(八)——自定义控件

《第一行代码》阅读笔记(八)——自定义控件

2020年07月23日  | 移动技术网IT编程  | 我要评论

在开发中我们经常会需要一些重复使用的控件或者控件组合,就比如安卓系统的三大金刚键,或者一些APP的顶部栏。如果我们为每个Activity都编写,不仅费时费力,而且维护性比较低。学过Java的朋友都应该知道,遇到这种情况,我们都是封装和抽取,然后再调用,所以安卓也不例外,下面就让我们用一个顶部栏作为例子展开学习吧。

引入布局

首先先设计共用布局。因为书上面是用了背景图片的,而笔者没有。所以做了一些调整。结果如下

源代码为

<?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"
    android:orientation="horizontal">

    <Button
        android:id="@+id/title_back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="top"

        android:text="Back"
        android:textColor="#fff" />

    <TextView
        android:id="@+id/title_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        android:layout_weight="1"
        android:layout_marginTop="3dp"
        android:background="#504E4E"
        android:gravity="center"
        android:text="Title Text"
        android:textColor="#fff"
        android:textSize="27sp" />

    <Button
        android:id="@+id/title_edit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Edit"
        android:textColor="#fff" />


</LinearLayout>

这里笔者有一个疑问,就是书中对所有控件都加了android:layout_gravity=“center”,但是这显然不对啊,添加后控件会变到屏幕中间,所有笔者将其改成了top。而且为了让三个控件可以对齐,笔者取消了按钮控件的margin,同时给textview加了一个margin。并且把textview的底色调成灰色了。

这里
android:background是添加背景的,可以是图片,也可以是颜色。
android:layout_margin是可以指定控件在上下左右方向上偏移的距离,同时可以android:layout_marginTop、android:layout_marginLeft等

在以后还会遇到一个和边界有关的属性,就是padding。

margin:
     需要在border外侧添加空白时;
     空白处不需要背景(色)时;
    上下相连的两个盒子之间的空白,需要相互抵消时。
padding:
    需要在border内测添加空白时;
    空白处需要背景(色)时;
    上下相连的两个盒子之间的空白,希望等于两者之和时。
————————————————
版权声明:本文为CSDN博主「你与温柔」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41155191/article/details/82798631

1是margin,2是padding

因为我们是在外部编写的布局文件,所以在使用时只需要调用即可,这里很好理解,就像封装的函数的调用。这里有两步,第一步引入,只需要一行代码

<include layout="@layout/title" />

第二步,因为我们想添加顶部栏,所以需要隐藏之前系统自动生成的

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.hide();
        }
    }

可以通过getSupportActionBar()来获得的ActionBar的实例,然后通过hide()来进行隐藏。

如何全局隐藏ActionBar

其实ActionBar也是一个非常实用控件,如果想了解的话可以看看下面的这篇文章
https://www.cnblogs.com/mjsn/p/6150824.html

自定义布局

引入布局可以解决很多问题,但是我们不能再为每个引入的布局绑定事件,这样还是不满足我们的需求。所有我们需要再封装,把事件也封装进入。

先创建一个类TitleLayout继承LinearLayout,并重写构造函数

public class TitleLayout extends LinearLayout {

    public TitleLayout(Context context, AttributeSet attrs){
        super(context,attrs);
        LayoutInflater.from(context).inflate(R.layout.title, this);
        
    }
}

——第一行代码
首先我们重写了LinearLayout中带有两个参数的构造函数,在布局中引入TitleLayout控件就会调用这个构造函数。然后在构造函数中需要对标题栏布局进行动态加载,这就要借助LayoutInflater来实现了。通过LayoutInflater的from ()方法可以构建出一个LayoutInflater对象,然后调用inflate()方法就可以动态加载一个布局文件,inflate( )方法接收两个参数,第一个参数是要加载的布局文件的id,这里我们传入R.layout.title, 第二个参数是给加载好的布局再添加一个父布局,这里我们想要指定为TitleLayout,于是直接传人this。

在主活动的布局文件中插入,和普通控件一样,只不过需要使用全类名。

<com.firstcode.uicustomviews.TitleLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />

修改TitleLayout类,添加响应事件。

public class TitleLayout extends LinearLayout {

    public TitleLayout(Context context, AttributeSet attrs){
        super(context,attrs);
        LayoutInflater.from(context).inflate(R.layout.title, this);
        Button titleBack = (Button) findViewById(R.id.title_back);
        Button titleEdit = (Button) findViewById(R.id.title_edit);
        titleBack.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                ((Activity)getContext()).finish();
            }
        });
        titleEdit.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getContext(),"You clicked Edit button",Toast.LENGTH_SHORT).show();
            }
        });
    }


}

这里我看书上使用了一个((Activity)getContext()).finish();不知道什么意思,书上也没解释,我推测是结束当前的环境,不是直接退出程序。但是这个demo只有一个主界面,所有我改成finish()并没有影响。

自定义控件

第一步:声明一个类,并继承View

public class RoundProgressBar extends View {

继承View是比较底层的控件了,其实也可以继承已有的控件,例如之前的LinearLayout或者Button。

第二步:构造函数

public RoundProgressBar(Context context) {
		this(context, null);
	}

	public RoundProgressBar(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public RoundProgressBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
     }

其实这种方法并不规范, 但是这样编写有个方便的地方,就是不管用哪种方法构造,都会到最后一个函数。

第三步:添加属性
在编写构造函数之前,还需要给这个控件添加一些私有属性。在Value中添加一个attr.xml文件

<declare-styleable name="circleProgressBar">
        <attr name="circleColor" format="color" />
        <attr name="circleProgressColor" format="color" />
        <attr name="circleWidth" format="dimension" />
        <attr name="textColor" format="color" />
        <attr name="textSize" format="dimension" />
        <attr name="max" format="integer" />
        <attr name="textIsDisplayable" format="boolean" />
        <attr name="newCircleMargin" format="dimension" />
        <attr name="style">
            <enum name="STROKE" value="0" />
            <enum name="FILL" value="1" />
        </attr>
    </declare-styleable>

声明一个这样的内容,declare-styleable name标签就是这个控件的名字,然后attr name标签就是属性的名字。

第四步:编写构造函数

  1. 首先声明一个paint类paint = new Paint();
  2. 实例化TypedArrayTypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.circleProgressBar);
  3. 给每个属性赋值roundColor = mTypedArray.getColor( R.styleable.circleProgressBar_circleColor, Color.RED);
  4. 回收 mTypedArray.recycle();

第五步:重写onDraw

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

其中canvas就是一个画布工具,可以对图形做出很多操作。在onDraw中需要对每个属性进行赋值,同时还可以进行一些逻辑的操作。

安卓中Paint类和Canvas类的方法汇总

第六步:使用自定义控件

<com.core.common.widget.RoundProgressBar
                    android:id="@+id/testlib_in_totalProgress"
                    android:layout_width="35dp"
                    android:layout_height="35dp"
                    android:layout_centerHorizontal="true"
                    android:layout_marginRight="25dp"
                    android:background="@drawable/ic_totalprogress"
                    android:clickable="true"
                    app:circleColor="#d8d8d8"
                    app:circleProgressColor="@color/blue"
                    app:circleWidth="2dp" />

其中android就是系统自带的属性,app就是自定义的属性。注意使用全类名!

本文地址:https://blog.csdn.net/SafeVidulInfo/article/details/107525628

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网