How to elegantly customize a View and Android custom view in android
The implementation of custom views in Android is relatively simple. It is nothing more than inheriting the parent class and then reloading the method. Even so, some pitfalls will inevitably occur in actual encoding, I will summarize some of my problems and solutions, and hope to help the majority of friends.
Note: ① When Layout is defined in xml, merge is recommended for the Root element.
When we need to inherit a ViewGroup with complicated layout (LinearLayout and RelativeLayout), we usually use xml to write the layout, then, in the Custom View class, inflate defines the layout xml file.
Create a new class file named MyLayout and parse the xml file later defined in the init method.
/** * Created by liangfei on 4/14/15. */public class MyLayout extends LinearLayout { public MyLayout(Context context) { super(context); init(); } private void init() { setOrientation(VERTICAL); View rootView = inflate(getContext(), R.layout.my_layout, this); ((TextView) rootView.findViewById(R.id.title)).setText("MyLayout"); ((TextView) rootView.findViewById(R.id.desc)).setText("A customized layout"); }}
Create a new nameMy_layoutLayout file, andRoot elementSetmerge
.
<?xml version="1.0" encoding="utf-8"?><merge xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:id="@+id/title" android:textSize="16sp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/desc" android:layout_width="wrap_content" android:layout_height="wrap_content" /></merge>
Use the Monitor tool that comes with the Android SDK to view the layout information during runtime.
The top layer is a FrameLayout, followed by a LinearLayout with two textviews. We can see that the layout is not redundant.
However, if you change the Root element to LinearLayout, what will happen?
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/title" android:textSize="16sp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/desc" android:layout_width="wrap_content" android:layout_height="wrap_content" /></LinearLayout>
Obviously, after using LinearLayout as the Root element, the layout has an extra level, which is a factor affecting performance.
Note: ② when reloading the subclass constructor, you need to find out what operations the parent class has performed.
First, I started with a painful lesson. At that time, I definedButton
:
/** * Created by liangfei on 4/14/15. */public class MyButton extends Button { public MyButton(Context context) { this(context, null); } public MyButton(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); }}
At first glance, it seems that there is no problem. The Calling method of the constructor is correct, but no matter how I modify the attributes of MyButton, the display method is incorrect.
Actually, the problem isButton
Class usesdefStyleAttr
And I will ignore this writing method.defStyleAttr
-com.android.internal.R.attr.buttonStyle
, Read the source code.
@RemoteViewpublic class Button extends TextView { public Button(Context context) { this(context, null); } public Button(Context context, AttributeSet attrs) { this(context, attrs, com.android.internal.R.attr.buttonStyle); } public Button(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public Button(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); }}
Later, when I wrote the code, I dared to write it after reading the source code of the parent class. If I was not sure, I would honestly write the following form.
/** * Created by liangfei on 4/14/15. */public class MyButton extends Button { public MyButton(Context context) { super(context, null); init(); } public MyButton(Context context, AttributeSet attrs) { super(context, attrs, 0); init(); } public MyButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); }}
In fact, there are many other pitfalls, such as the height of the Button, which will be summarized later. It's too sleepy to go to bed.
When there are too many other users