Click "Android Technology Grocery Store" above and select "Top Public Number"
Dry article, first time service!
Author: Android Grassroots King
Link: https://www.jianshu.com/p/e538b35c68c3
This article is authorized by the author.
Custom controls are used in many parts of the project.
Simple points, such as customization of personality control, combination packaging of multiple components, etc.
We need to understand the basic knowledge of custom controls, which can be implemented quickly.
Complex points, such as various graphical reports (e.g. stock K-line chart, time-sharing chart control).
In addition to the basic knowledge of custom controls, we also need to master the control event interception and transmission mechanism, event callback, gesture recognition, drawing, animation, architecture design and other technologies.
With regard to custom controls, we will step by step elaborate on:
Today, we first implement a simple custom control, and later find time to explain how to customize the stock K-line chart and time-sharing chart control.
demand
Realize the mobile phone number input box with animation effect:
1. Input mobile phone number format is 3-4-4; 2. The default hint prompt in the input box has animation effect when the number is input: (a) hint moves out of the input box and stays at the specified position above the input box to display the corresponding information; (b) In the translation process, the text gradually changes from big to small; 3. When the input box is cleared, the negative effect animation is made. 4. Automatically verify the digital format (non-digital is not allowed to enter) and the length of the input (up to 11 mobile phone numbers) 5. When the input box is valid, the empty button appears on the far right and clicks the empty input box. 6. Input completed, callback results;
Analysis
This input box effect will be used in many pages, we must encapsulate it, the best encapsulation scheme here is the custom control.
In our APP, the input logic of mobile phone number input box of all pages is exactly the same, but there are small differences between individual pages (when individual pages enter mobile phone number, there is no need for animation effect, or hint content, prompt message is different, etc.).
1. Differences should be configurable:
The following contents of a custom control should be designed as configurable properties:
Is there animation effect? hint text; hint moves to the text displayed at the top, etc. The emphasis here is: 1. How to configure custom attributes? How to use it?
2. Custom controls are called (used)
We should support direct new controls in our code We should support direct use of our controls in layout xml, configurable custom properties
3, animation
Translational effect: Tween animation, attribute animation can be achieved; Font Scaling: Attribute animation should be used to scale according to font size, width and height will automatically change (Note: Tween animation can not do font size difference change) To sum up, attribute animation should be used uniformly to achieve translation and scaling effects, while multiple animations triggered simultaneously, and animation sets will be used. The emphasis here is: 1. Translating requires two coordinates (x,y) of the original point and the target point. How to get the corresponding value in the custom control? 2. Font scaling requires two font size values before and after scaling. The default font size obtained in the code is px format. How to convert it to sp? 3. Design point: To achieve the animation effect of text movement and font size scaling, we can place two text controls in the layout. tv_message: As hint placeholder, not displayed, only used to obtain coordinates and fonts; tv_to_message: Display as top message, display as hint, animation is executed on the control; Of course, there are many other ways to design this animation effect. When you use it, you can design it reasonably according to your own needs.
4. The 3-4-4 format of mobile phone number is to intercept input events and process strings. There is no technical point.
5. The length of mobile phone number and special characters are prohibited from input verification, and illegal characters can be judged by regular expressions.
6. Other:
Technical Implementation Analysis
The definition of attributes needs to be defined separately in the files under res:
In the res/values directory, create the attrs.xml file
<?xml version="1.0" encoding="utf-8"?> <resources> <!--user-Mobile Number Input Control-Custom Properties--> <declare-styleable name="user.phone.edittext"> <attr name="showTopMessage" format="boolean"/> <attr name="topMessage" format="string"/> <attr name="hint" format="string"/> </declare-styleable> </resources>
name can be customized and standardized.
showTopMessage // Custom Properties: Whether to Display Top Tips (true: display, false: not display)
topMessage//Custom Properties: Top Tip Information Content
hint // custom property: input box prompt information
2. Layout of custom controls
Use relative layout, including:
Enter box et_phone (need to be set to no background color, because UI personnel have fixed the input line color)
The bottom line of the input box View,
The empty button iv_phone_clear of the input box,
The text control tv_message above the input box (used as a placeholder for hint positions and fonts)
The text control tv_to_message at the top of the input box (for displaying prompt information)
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="10dip" android:paddingRight="10dip"> <TextView android:id="@+id/tv_to_message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:textColor="#999999" android:textSize="14sp" android:text="Please enter your cell phone number." android:visibility="visible"/> <RelativeLayout android:layout_width="match_parent" android:layout_height="40dp" android:id="@+id/rl" android:layout_below="@+id/tv_to_message"> <ImageView android:id="@+id/iv_phone_clear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerInParent="true" android:src="@mipmap/close_white" android:visibility="invisible" /> <EditText android:id="@+id/et_phone" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_toLeftOf="@+id/iv_phone_clear" android:background="@null" android:inputType="phone" android:textColor="#2A2A2A" android:textColorHint="#999999" android:textSize="16sp" /> <TextView android:id="@+id/tv_message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="false" android:textColor="#999999" android:gravity="center_vertical" android:layout_centerVertical="true" android:textSize="16sp" android:text="Please enter your cell phone number." android:visibility="invisible"/> <View android:layout_width="match_parent" android:layout_height="1dp" android:layout_alignParentBottom="true" android:background="#EBEBEB" /> </RelativeLayout> </RelativeLayout>
3. Create custom control classes (defined as new controls that can be used directly in xml)
Constructor: Custom controls must use specific constructors: 1. A constructor for a parameter that can be used to directly new current controls in other code UserPhoneEditText(Context context) 2. Constructors with more than two parameters can be used to directly use the current control in layout xml, and AttributeSet can be used to obtain the properties we set in xml; (explained later) UserPhoneEditText(Context context, AttributeSet attrs) More constructor-related information, please find the information yourself!!!
The code parses to get custom parameters:
//Get the set of attributes defined in attrs. XML UserPhone EditText TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.user_phone_edittext); showTopMessage = typedArray.getBoolean(R.styleable.user_phone_edittext_showTopMessage, false); topMessage = typedArray.getString(R.styleable.user_phone_edittext_topMessage); hint = typedArray.getString(R.styleable.user_phone_edittext_hint); //release typedArray.recycle(); 1. R.styleable.user_phone_edittext We are here. res/attrs.xml Names defined in the id 2. When you get the parameters, you must remember to TypedArray Release, remember!!!
Create custom controls and get detailed code for custom parameters:
/** * Class: UserPhone EditText * Author: qxc * Date: 2018/3/2. */ public class UserPhoneEditText extends RelativeLayout { private Context context;//context private boolean showTopMessage;//Custom Properties: Whether to Display Top Tips (true: display, false: not display) private String topMessage;//Custom Properties: Top Tip Information Content private String hint;//Input box prompt information private EditText et_phone;//Telephone Number Input Box private ImageView iv_phone_clear;//Clear the input box button private TextView tv_message;//Message text in input box private TextView tv_to_message;//Out-of-box message text public UserPhoneEditText(Context context) { super(context); this.context = context; LoadView(context); } public UserPhoneEditText(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; getAttrs(context,attrs); LoadView(context); } /** * Get custom attributes for configuration * @param context context * @param attrs Attribute set */ private void getAttrs(Context context,AttributeSet attrs){ //Get the set of attributes defined in attrs. XML UserPhone EditText TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.user_phone_edittext); showTopMessage = typedArray.getBoolean(R.styleable.user_phone_edittext_showTopMessage, false); topMessage = typedArray.getString(R.styleable.user_phone_edittext_topMessage); hint = typedArray.getString(R.styleable.user_phone_edittext_hint); //release typedArray.recycle(); } /** * Initialize view * @param context context */ private void LoadView(Context context){ View view = LayoutInflater.from(context).inflate(R.layout.user_phone_edittext, this); initView(view);//Initialization component initEvent();//Initialization events } /** * Initialization component */ private void initView(View view){ et_phone = (EditText) view.findViewById(R.id.et_phone); iv_phone_clear = (ImageView) view.findViewById(R.id.iv_phone_clear); tv_message = (TextView) view.findViewById(R.id.tv_message); tv_to_message = (TextView) view.findViewById(R.id.tv_to_message); //Display components according to custom properties //Setting Text Information if(topMessage!=null){ tv_to_message.setText(hint); } } /** * Initialization events */ private void initEvent(){ //Clear the contents of the input box iv_phone_clear.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { et_phone.setText(""); } }); //Input Box Content Change Event //If the input box starts typing characters, tv_message uses animation to move to the location of tv_to_message. //If the input box becomes empty, tv_message moves back from the location of tv_to_message et_phone.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void afterTextChanged(Editable editable) { String text = editable.toString(); if (text.length() == 0) { //Clear the input box //Execution animation } } //If the input box starts typing characters, tv_message uses animation to move to the location of tv_to_message. else if (text.length() == 1 && tvPosition == 0) { //Change of input box content //Execution animation //When the 11-digit mobile phone number is entered, the execution result callback } } }); } }
4. The execution of animation
Animation 1: Flat Moving Painting
Two coordinate points need to be obtained: Coordinate point 1: hint text position (tv_message) Coordinate Point 2: The location of message text (tv_top_message) Let's first define two values to store coordinates of coordinate points. private int[] position1 = new int[2];//tv_message's default location coordinates Private int [] position 2 = New Int [2]; //tv_to_message's default location coordinates x moves, y moves, so use animation set AnimatorSet If it's just moving, the code is as follows: AnimatorSet set = new AnimatorSet(); set.playTogether( ObjectAnimator.ofFloat(tv_to_message , "TranslationX" , startX , endX), ObjectAnimator.ofFloat(tv_to_message , "TranslationY" ,startY, endY)); set.setDuration(duration).start();
Be careful:
startX and endX equivalents do not refer to the absolute coordinate address on the screen (e.g. coordinates (200,200)), but to the numerical change of translation on the x axis.
For example:
startX = 0 indicates that the X position of the current control changes to 0.
endX =100 means moving 100 pixels to the right starting from startX.
EndX = 100 means moving 100 pixels to the left starting from startX.
After ofFloat, the value of X can be added to represent the path process of movement on the X axis.
Our actual startX and endX values are subtracted from the coordinate X of tv_message and tv_top_message, that is, the relative distance of the control is calculated as the distance or position of the animation movement.
Animation 2: Size change
The font value of two texts needs to be obtained( tv_message,tv_top_message) //Let's first define an array to store the font values of two texts. private float[] fonts = new float[2];//Default size of tv_to_message //Animation execution, if the font is scaled while moving, can continue to use AnimatorSet, the code will be transformed into: /** * Play animation * @param startX Start X * @param endX Target X * @param startY Start Y * @param endY Target Y * @param startFont Start font size * @param endFont Target font size */ private void startAnim(float startX, float endX, float startY, float endY, float startFont, float endFont){ AnimatorSet set = new AnimatorSet(); set.playTogether( ObjectAnimator.ofFloat(tv_to_message , "TranslationX" , startX , endX), ObjectAnimator.ofFloat(tv_to_message , "TranslationY" ,startY, endY), ObjectAnimator.ofFloat(tv_to_message , "TextSize" , startFont, endFont)); set.setDuration(duration).start(); }
A key:
How to get the coordinates and size of tv_message, tv_top_message in the custom control?
Custom controls have their own function cycles, and different functions do different things. Such as onSizeChanged, onMeasure, onLayout, onDraw, etc. If you do not understand what these methods do, please look for information on your own.
Let's write a code to do an experiment. First, let's look at the execution order of the custom control functions.
Customize a simple view to test the code:
package iwangzhe.testcustomview; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; /** * Class: TestView * Author: qxc * Date: 2018/2/27. */ public class TestView extends View { final String Tag = "TestView"; public TestView(Context context, AttributeSet attrs) { super(context, attrs); Log.i(Tag,"Constructor TestView"); } @Override protected void onFinishInflate() { super.onFinishInflate(); Log.i(Tag,"onFinishInflate"); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); Log.i(Tag,"onMeasure"); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); Log.i(Tag,"onLayout"); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); Log.i(Tag,"onSizeChanged"); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Log.i(Tag,"onDraw"); } @Override public boolean onTouchEvent(MotionEvent event) { Log.i(Tag,"onTouchEvent"); invalidate(); return super.onTouchEvent(event); } @Override protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); Log.i(Tag,"onFocusChanged"); } @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); Log.i(Tag,"onWindowFocusChanged"); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); Log.i(Tag,"onAttachedToWindow"); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); Log.i(Tag,"onDetachedFromWindow"); } @Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); Log.i(Tag,"onWindowVisibilityChanged"); } }
Output results:
03-05 17:38:55.690 23189-23189/iwangzhe.testcustomview I/TestView: Constructor TestView 03-05 17:38:55.690 23189-23189/iwangzhe.testcustomview I/TestView: onFinishInflate 03-05 17:38:55.770 23189-23189/iwangzhe.testcustomview I/TestView: onAttachedToWindow 03-05 17:38:55.770 23189-23189/iwangzhe.testcustomview I/TestView: onWindowVisibilityChanged 03-05 17:38:55.780 23189-23189/iwangzhe.testcustomview I/TestView: onMeasure 03-05 17:38:55.780 23189-23189/iwangzhe.testcustomview I/TestView: onMeasure 03-05 17:38:55.820 23189-23189/iwangzhe.testcustomview I/TestView: onSizeChanged 03-05 17:38:55.820 23189-23189/iwangzhe.testcustomview I/TestView: onLayout 03-05 17:38:55.830 23189-23189/iwangzhe.testcustomview I/TestView: onDraw 03-05 17:38:55.860 23189-23189/iwangzhe.testcustomview I/TestView: onWindowFocusChanged 03-05 17:38:55.880 23189-23189/iwangzhe.testcustomview I/TestView: onMeasure 03-05 17:38:55.880 23189-23189/iwangzhe.testcustomview I/TestView: onMeasure 03-05 17:38:55.880 23189-23189/iwangzhe.testcustomview I/TestView: onLayout 03-05 17:38:55.880 23189-23189/iwangzhe.testcustomview I/TestView: onDraw ......(repeat onMeasure,onLayout,onDraw)
We see that the onWindows FocusChanged method will be executed after the page loads the custom control. Before this method, initialization, calculation, layout and drawing display have been performed, and the position of the control has been assigned. So in the onWindows FocusChanged method, we can get the corresponding attributes, the code is as follows:
/** * Custom control is ready to get the location and other data of each component. */ @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); //Get location information for message text tv_message.getLocationInWindow(position1); tv_to_message.getLocationOnScreen(position2); //Get the font information of the message text fonts[0] = PxUtils.px2sp(context,tv_message.getTextSize()); fonts[1] = PxUtils.px2sp(context,tv_to_message.getTextSize()); //Initialization location, number (tv_to_message setting is consistent with tv_message display) tv_to_message.setTextSize(fonts[0]); tv_to_message.setTranslationX(position1[0]-position2[0]); tv_to_message.setTranslationY(position1[1]-position2[1]); }
5. Mobile phone number 3-4-4 format
The code is relatively simple, as follows:
/** * Telephone 344 format (i.e., XXXX XXX xxx) * Telephone length 11 digits * @param view Input box * @param text text */ public static void onTextChanged344(EditText view, String text) { if (view== null || text == null || text.length() == 0) return; char space = ' '; int indexSpace1 = 3; int indexSpace2 = 8; StringBuilder sb = new StringBuilder(); //1. Remove all characters, remove''and illegal characters for (int i = 0; i < text.length(); i++) { //If the number of digits is greater than 11 digits, remove the following digits if(sb.length() >= 11){ break; } //Valid Characters (0-9) (Regular Expressions) Pattern pattern = Pattern.compile("^[0-9]*$"); Matcher matcher = pattern.matcher(String.valueOf(text.charAt(i))); if (text.charAt(i) != space && matcher.matches()) { sb.append(text.charAt(i)); } } //2. Adding''according to length if(sb.length() > indexSpace1){ sb.insert(indexSpace1, space); } if(sb.length() > indexSpace2){ sb.insert(indexSpace2, space); } //3. Setting text and cursor positions if(!sb.toString().equals(text)){ view.setText(sb.toString()); view.setSelection(sb.length()); } }
Complete code
Above, the basic technical points have been solved, so let's string up the code and paste out the complete code (the Demo source address will be given later).
Class 1: Help Class for PxUtils px and sp Conversion
/** * Class: PxUtils * Author: qxc * Date: 2018/3/5. */ public class PxUtils { /** * px Turn sp * @param context context * @param pxValue px * @return sp */ public static int px2sp(Context context, float pxValue) { final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; return (int) (pxValue / fontScale + 0.5f); } }
Class 2: Telephone number format processing class
/** * Class: PhoneFormat * Author: qxc * Date: 2018/3/5. */ public class PhoneFormat { /** * Telephone 344 format (i.e., XXXX XXX xxx) * Telephone length 11 digits * @param view Input box * @param text text */ public static void onTextChanged344(EditText view, String text) { if (view== null || text == null || text.length() == 0) return; char space = ' '; int indexSpace1 = 3; int indexSpace2 = 8; StringBuilder sb = new StringBuilder(); //1. Remove all characters, remove''and illegal characters for (int i = 0; i < text.length(); i++) { //If the number of digits is greater than 11 digits, remove the following digits if(sb.length() >= 11){ break; } //Valid Characters (0-9) Pattern pattern = Pattern.compile("^[0-9]*$"); Matcher matcher = pattern.matcher(String.valueOf(text.charAt(i))); if (text.charAt(i) != space && matcher.matches()) { sb.append(text.charAt(i)); } } //2. Adding''according to length if(sb.length() > indexSpace1){ sb.insert(indexSpace1, space); } if(sb.length() > indexSpace2){ sb.insert(indexSpace2, space); } //3. Setting text and cursor positions if(!sb.toString().equals(text)){ view.setText(sb.toString()); view.setSelection(sb.length()); } } /** * Get the phone number entered, excluding spaces * @param editText Input control * @return Telephone number */ public static String getPhoneNumber(EditText editText){ if (editText== null || editText.getText() == null) return ""; String text = editText.getText().toString(); char space = ' '; StringBuilder sb = new StringBuilder(); for (int i = 0; i < text.length(); i++) { if (text.charAt(i) != space) { sb.append(text.charAt(i)); } } return sb.toString(); } }
Class 3: Custom control class (core class)
/** * Class: UserPhone EditText * Author: qxc * Date: 2018/3/2. */ public class UserPhoneEditText extends RelativeLayout { private Context context;//context private boolean showTopMessage;//Custom Properties: Whether to Display Top Tips (true: display, false: not display) private String topMessage;//Custom Properties: Top Tip Information Content private String hint;//Input box prompt information private EditText et_phone;//Telephone Number Input Box private ImageView iv_phone_clear;//Clear the input box button private TextView tv_message;//Message text in input box private TextView tv_to_message;//Out-of-box message text private int duration = 200;//Animation execution time private int tvPosition = 0;//The current location of tv_message, 0: in the input box; 1: in the location of tv_to_message (judgement before animation) private int[] position1 = new int[2];//Default position coordinates of tv_message private int[] position2 = new int[2];//Default position coordinates of tv_to_message private float[] fonts = new float[2];//Default size of tv_to_message public UserPhoneEditText(Context context) { super(context); this.context = context; LoadView(context); } public UserPhoneEditText(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; getAttrs(context,attrs); LoadView(context); } /** * Get custom attributes for configuration * @param context context * @param attrs Attribute set */ private void getAttrs(Context context,AttributeSet attrs){ //Get the set of attributes defined in attrs. XML UserPhone EditText TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.user_phone_edittext); showTopMessage = typedArray.getBoolean(R.styleable.user_phone_edittext_showTopMessage, false); topMessage = typedArray.getString(R.styleable.user_phone_edittext_topMessage); hint = typedArray.getString(R.styleable.user_phone_edittext_hint); //release typedArray.recycle(); } /** * Initialize view * @param context context */ private void LoadView(Context context){ View view = LayoutInflater.from(context).inflate(R.layout.user_phone_edittext, this); initView(view);//Initialization component initEvent();//Initialization events } /** * Initialization component */ private void initView(View view){ et_phone = (EditText) view.findViewById(R.id.et_phone); iv_phone_clear = (ImageView) view.findViewById(R.id.iv_phone_clear); tv_message = (TextView) view.findViewById(R.id.tv_message); tv_to_message = (TextView) view.findViewById(R.id.tv_to_message); //Display components according to custom properties //Setting Text Information if(topMessage!=null){ tv_to_message.setText(hint); } } /** * Initialization events */ private void initEvent(){ //Clear the contents of the input box iv_phone_clear.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { et_phone.setText(""); } }); //Input Box Content Change Event //If the input box starts typing characters, tv_message uses animation to move to the location of tv_to_message. //If the input box becomes empty, tv_message moves back from the location of tv_to_message et_phone.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void afterTextChanged(Editable editable) { String text = editable.toString(); //If the input box becomes empty, tv_message moves back from the location of tv_to_message if (text.length() == 0) { iv_phone_clear.setVisibility(View.INVISIBLE); //If you don't display the top message, you don't need the animation effect. if(!showTopMessage) { tv_to_message.setVisibility(VISIBLE); }else { tvPosition = 0; float startX = 0; float endX = position1[0] - position2[0]; float startY = 0; float endY = position1[1] - position2[1]; //Execution animation startAnim(startX, endX, startY, endY, fonts[1], fonts[0]); tv_to_message.setText(hint); } } //If the input box starts typing characters, tv_message uses animation to move to the location of tv_to_message. else if (text.length() == 1 && tvPosition == 0) { iv_phone_clear.setVisibility(View.VISIBLE); if(!showTopMessage) { tv_to_message.setVisibility(INVISIBLE); }else { tvPosition = 1; float startX = position1[0] - position2[0]; float endX = 0; float startY = position1[1] - position2[1]; float endY = 0; //Execution animation startAnim(startX, endX, startY, endY, fonts[0], fonts[1]); tv_to_message.setText(topMessage); } } //344 Telephone Format Processing PhoneFormat.onTextChanged344(et_phone,editable.toString()); //Callback if(et_phone.getText().length()==13&&onSuccessListener!=null){ onSuccessListener.onSuccess(et_phone.getText().toString()); } } }); } /** * Custom control is ready to get the location and other data of each component. */ @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); //Get location information for message text tv_message.getLocationInWindow(position1); tv_to_message.getLocationOnScreen(position2); //Get the font information of the message text fonts[0] = PxUtils.px2sp(context,tv_message.getTextSize()); fonts[1] = PxUtils.px2sp(context,tv_to_message.getTextSize()); //Initialization location, number (tv_to_message setting is consistent with tv_message display) tv_to_message.setTextSize(fonts[0]); tv_to_message.setTranslationX(position1[0]-position2[0]); tv_to_message.setTranslationY(position1[1]-position2[1]); } /** * Play animation * @param startX Start X * @param endX Target X * @param startY Start Y * @param endY Target Y * @param startFont Start font size * @param endFont Target font size */ private void startAnim(float startX, float endX, float startY, float endY, float startFont, float endFont){ AnimatorSet set = new AnimatorSet(); set.playTogether( ObjectAnimator.ofFloat(tv_to_message , "TranslationX" , startX , endX), ObjectAnimator.ofFloat(tv_to_message , "TranslationY" ,startY, endY), ObjectAnimator.ofFloat(tv_to_message , "TextSize" , startFont, endFont)); set.setDuration(duration).start(); } /** * Get the input phone number * @return Input telephone number */ public String getPhone(){ return PhoneFormat.getPhoneNumber(et_phone); } /** * Get the input phone number for display * @return Input telephone number 334 format */ public String getText(){ return et_phone.getText().toString(); } /** * Input completion callback */ public interface OnSuccessListener{ /** * Input complete * @param phone Telephone number */ void onSuccess(String phone); } private OnSuccessListener onSuccessListener; /** * Set up monitoring * @param onSuccessListener */ public void setOnSuccessListener(OnSuccessListener onSuccessListener){ this.onSuccessListener = onSuccessListener; } }
Layout: user_phone_edittext.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="10dip" android:paddingRight="10dip"> <TextView android:id="@+id/tv_to_message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:textColor="#999999" android:textSize="14sp" android:text="Please enter your cell phone number." android:visibility="visible"/> <RelativeLayout android:layout_width="match_parent" android:layout_height="40dp" android:id="@+id/rl" android:layout_below="@+id/tv_to_message"> <ImageView android:id="@+id/iv_phone_clear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerInParent="true" android:src="@mipmap/close_white" android:visibility="invisible" /> <EditText android:id="@+id/et_phone" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_toLeftOf="@+id/iv_phone_clear" android:background="@null" android:inputType="phone" android:textColor="#2A2A2A" android:textColorHint="#999999" android:textSize="16sp" /> <TextView android:id="@+id/tv_message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="false" android:textColor="#999999" android:gravity="center_vertical" android:layout_centerVertical="true" android:textSize="16sp" android:text="Please enter your cell phone number." android:visibility="invisible"/> <View android:layout_width="match_parent" android:layout_height="1dp" android:layout_alignParentBottom="true" android:background="#EBEBEB" /> </RelativeLayout> </RelativeLayout>Custom Properties attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <!--user-Mobile Number Input Control-Custom Properties--> <declare-styleable name="user.phone.edittext"> <attr name="showTopMessage" format="boolean"/> <attr name="topMessage" format="string"/> <attr name="hint" format="string"/> </declare-styleable> </resources>
Test class MainActivity (test call custom control)
.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:userphoneedittext="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="iwangzhe.testcustomview.MainActivity"> <Button android:layout_width="match_parent" android:layout_height="50dp" android:id="@+id/btn2" android:text="B" android:visibility="gone"/> <Button android:layout_width="match_parent" android:layout_height="50dp" android:id="@+id/btn1" android:layout_below="@id/btn2" android:text="A" android:visibility="gone"/> <iwangzhe.testcustomview.TestView android:layout_below="@id/btn1" android:layout_width="match_parent" android:layout_height="20dp" android:id="@+id/tv1"/> <iwangzhe.testcustomview.userphone.UserPhoneEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/tv1" android:id="@+id/upet1" userphoneedittext:showTopMessage="true" userphoneedittext:topMessage="Test message information" userphoneedittext:hint="default hint Message information"> </iwangzhe.testcustomview.userphone.UserPhoneEditText> <Button android:text="Verification of mobile phone number" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="18dp" android:id="@+id/btnPhone" android:layout_below="@+id/upet1" android:layout_centerHorizontal="true" /> </RelativeLayout>
To use custom attributes, we need to set the naming control: xmlns:userphoneedittext="http://schemas.android.com/apk/res-auto";
Userphone EditText can be defined by itself, and other formats are fixed.
public class MainActivity extends BaseActivity { Button btn1; Button btn2; Button btnPhone; UserPhoneEditText upet; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnPhone = (Button) findViewById(R.id.btnPhone); upet = (UserPhoneEditText) findViewById(R.id.upet1); //Set up callback monitor to get input completed callback data (passive callback) upet.setOnSuccessListener(new UserPhoneEditText.OnSuccessListener(){ @Override public void onSuccess(String phone) { Toast.makeText(MainActivity.this, phone, Toast.LENGTH_SHORT).show(); } }); //Get text information for custom controls (active acquisition) btnPhone.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String text = upet.getPhone(); Toast.makeText(MainActivity.this,text,Toast.LENGTH_SHORT).show(); } }); } }
If you still don't understand Demo, please leave a message or check your own information.
This article is mainly to let you know the process of custom control. If you want to use it in your own project, please adjust and optimize it according to your needs.
Demo address:
https://pan.baidu.com/s/1g5Ro3ZUWcdLwQezSmYFrBA
Dry goods in the past
1
Summary of MPAndroid Chart Curve Drawing
2
Mobile Card of Demand Solution Series I to Realize Answering Function
3
How to gracefully implement Android fingerprint verification in complex business scenarios?