English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
The graduation project uses custom controls in many places, and I have always intended to summarize the implementation methods of custom controls. Today, I will summarize them. Before that, I learned several articles about custom View from the blog of God Guolin, and I found it very beneficial. This article refers to some of the content in it.
In summary, there are three ways to implement custom controls, namely: composite controls, hand-drawn controls, and inherited controls. Below, we will introduce these three methods respectively.
(I) Composite Controls
Composite controls, as the name implies, are a combination of some small controls to form a new control. These small controls are mostly system-provided controls. For example, the title bar control commonly used in many applications is actually a composite control. Therefore, the following will explain the usage of composite controls by implementing a simple custom title bar control.
1Create a new Android project and create a custom title bar layout file title_bar.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:background="#0000ff" > <Button android:id="@"+id/left_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_margin="5dp" android:background="@drawable/back1_64" /> <TextView android:id="@"+id/title_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="This is the title" android:textColor="#ffffff" android:textSize="20sp" /> </RelativeLayout>
As can be seen, this title bar control is relatively simple, with a return button on the left and a background image back prepared in advance.1_64.png, the title text is in the middle of the title bar.
2Create a class TitleView, inheriting from RelativeLayout:
public class TitleView extends RelativeLayout { // Return button control private Button mLeftBtn; // Title Tv private TextView mTitleTv; public TitleView(Context context, AttributeSet attrs) { super(context, attrs); // Load layout LayoutInflater.from(context).inflate(R.layout.title_bar, this); // Obtain controls mLeftBtn = (Button) findViewById(R.id.left_btn); mTitleTv = (TextView) findViewById(R.id.title_tv); } // Add a custom click event to the left back button public void setLeftButtonListener(OnClickListener listener) { mLeftBtn.setOnClickListener(listener); } // Method to set the title public void setTitleText(String title) { mTitleTv.setText(title); } }
In TitleView, the main task is to load the layout for the custom title bar, add event listener methods for the back button, and provide methods to set the title text.
3In activity_main.xml, import the custom title bar:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@"+id/main_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.example.test.TitleView android:id="@"+id/title_bar" android:layout_width="match_parent" android:layout_height="wrap_content" > </com.example.test.TitleView> </LinearLayout>
4In MainActivity, obtain the custom title bar and add a custom click event to the back button:
private TitleView mTitleBar; mTitleBar = (TitleView) findViewById(R.id.title_bar); mTitleBar.setLeftButtonListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "Clicked the back button", Toast.LENGTH_SHORT) .show(); finish(); } });
5The running effect is as follows:
In this way, a custom title bar is implemented by combining, and more combinations can create more complex custom controls, such as custom search bars, etc.
(ii) Self-drawn control
All the content of the self-drawn control is drawn by itself, completed in the View's onDraw method. Below is an implementation of a simple counter, the count value increases each time it is clicked.1and display it.
1Create the CounterView class, inheriting from View and implementing the OnClickListener interface:
public class CounterView extends View implements OnClickListener { // Define the paint private Paint mPaint; // Used to get the width and height of the text private Rect mBounds; // Count value, the value increases each time this control is clicked1 private int mCount; public CounterView(Context context, AttributeSet attrs) { super(context, attrs); // Initialize the paint and Rect mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBounds = new Rect(); // The click event of this control setOnClickListener(this); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.BLUE); // Draw a rectangle with blue fill color canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint); mPaint.setColor(Color.YELLOW); mPaint.setTextSize(50); String text = String.valueOf(mCount); // Get the width and height of the text mPaint.getTextBounds(text, 0, text.length(), mBounds); float textWidth = mBounds.width(); float textHeight = mBounds.height(); // Draw string canvas.drawText(text, getWidth() / 2 - textWidth / 2, getHeight() / 2 + textHeight / 2, mPaint); } @Override public void onClick(View v) { mCount ++; // Redraw invalidate(); } }
2In activity_main.xml, introduce the custom layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@"+id/main_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.example.test.CounterView android:id="@"+id/counter_view" android:layout_width="100dp" android:layout_height="100dp" android:layout_gravity="center_horizontal|top" android:layout_margin="20dp" /> </LinearLayout>
3The running effect is as follows:
(3) Inheriting controls
It is to inherit existing controls, create new controls, retain the characteristics of the inherited parent controls, and can also introduce new features. Below, we will introduce the implementation of a custom ListView that supports horizontal swiping to delete list items.
1Create the delete button layout delete_btn.xml, which is displayed after horizontal swiping a list item:
<?xml version="1.0" encoding="utf-8"?> <Button xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#FF0000" android:padding="5dp" android:text="Delete" android:textColor="#FFFFFF" android:textSize="16sp" > </Button>
2Create the CustomListView class, inheriting from ListView, and implementing the OnTouchListener and OnGestureListener interfaces:
public class CustomListView extends ListView implements OnTouchListener, OnGestureListener { // Gesture detection action detector private GestureDetector mGestureDetector; // Delete event listener public interface OnDeleteListener { void onDelete(int index); } private OnDeleteListener mOnDeleteListener; // Delete button private View mDeleteBtn; // List item layout private ViewGroup mItemLayout; // The selected list item private int mSelectedItem; // Whether the current delete button is displayed private boolean isDeleteShown; public CustomListView(Context context, AttributeSet attrs) { super(context, attrs); // Create a gesture listener object mGestureDetector = new GestureDetector(getContext(), this); // Listen to onTouch event setOnTouchListener(this); } // Set delete listening event public void setOnDeleteListener(OnDeleteListener listener) { mOnDeleteListener = listener; } // Touch listening event @Override public boolean onTouch(View v, MotionEvent event) { if (isDeleteShown) { hideDelete(); return false; } else { return mGestureDetector.onTouchEvent(event); } } @Override public boolean onDown(MotionEvent e) { if (!isDeleteShown) { mSelectedItem = pointToPosition((int) e.getX(), (int) e.getY()); } return false; } @Override public boolean onFling(MotionEvent e1, MotionEvent e}}2, float velocityX, float velocityY) { // If the current delete button is not displayed and the sliding speed in the x direction is greater than the sliding speed in the y direction if (!isDeleteShown && Math.abs(velocityX) > Math.abs(velocityY)) { mDeleteBtn = LayoutInflater.from(getContext()).inflate( R.layout.delete_btn, null); mDeleteBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mItemLayout.removeView(mDeleteBtn); mDeleteBtn = null; isDeleteShown = false; mOnDeleteListener.onDelete(mSelectedItem); } }); mItemLayout = (ViewGroup) getChildAt(mSelectedItem) - getFirstVisiblePosition()); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); params.addRule(RelativeLayout.CENTER_VERTICAL); mItemLayout.addView(mDeleteBtn, params); isDeleteShown = true; } return false; } // Hide the delete button public void hideDelete() { mItemLayout.removeView(mDeleteBtn); mDeleteBtn = null; isDeleteShown = false; } public boolean isDeleteShown() { return isDeleteShown; } /** * The following methods are not used in this example */ @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return false; } @Override public boolean onScroll(MotionEvent e)1, MotionEvent e}}2, float distanceX, float distanceY) { return false; } @Override public void onLongPress(MotionEvent e) { } }
3Define the list item layout custom_listview_item.xml, which has a simple structure, containing only a TextView:
<?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="match_parent" android:descendantFocusability="blocksDescendants" > <TextView android:id="@"+id/content_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_margin="30dp" android:gravity="center_vertical|left" /> </RelativeLayout>
4Define the adapter class CustomListViewAdapter, inheriting from ArrayAdapter<String>:
public class CustomListViewAdapter extends ArrayAdapter<String> { public CustomListViewAdapter(Context context, int textViewResourceId, List<String> objects) { super(context, textViewResourceId, objects); } @Override public View getView(int position, View convertView, ViewGroup parent) { View view; if (convertView == null) { view = LayoutInflater.from(getContext()).inflate( R.layout.custom_listview_item, null); } else { view = convertView; } TextView contentTv = (TextView) view.findViewById(R.id.content_tv); contentTv.setText(getItem(position)); return view; } }
5In activity_main.xml, import the custom ListView:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@"+id/main_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.example.test.CustomListView android:id="@"+id/custom_lv" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
6In MainActivity, initialize the list, set the click event for the delete button of the list item, and other processing:
public class MainActivity extends Activity { // Custom Lv private CustomListView mCustomLv; // Custom Adapter private CustomListViewAdapter mAdapter; // Content List private List<String> contentList = new ArrayList<String>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); initContentList(); mCustomLv = (CustomListView) findViewById(R.id.custom_lv); mCustomLv.setOnDeleteListener(new OnDeleteListener() { @Override public void onDelete(int index) { contentList.remove(index); mAdapter.notifyDataSetChanged(); } }); mAdapter = new CustomListViewAdapter(this, 0, contentList); mCustomLv.setAdapter(mAdapter); } // Initialize content list private void initContentList() { for (int i = 0; i < 20; i++) { contentList.add("Content Item" + i); } } @Override public void onBackPressed() { if (mCustomLv.isDeleteShown()) { mCustomLv.hideDelete(); return; } super.onBackPressed(); } }
7The running effect is as follows:
That's all for this article, I hope it will be helpful to everyone's learning, and I also hope everyone will support the Yelling Tutorial more.
Statement: The content of this article is from the Internet, the copyright belongs to the original author, the content is contributed and uploaded by Internet users spontaneously, this website does not own the copyright, has not been edited by humans, and does not assume relevant legal liabilities. If you find any content suspected of copyright infringement, please send an email to: notice#w3Please report via email to codebox.com (replace # with @ when sending email) and provide relevant evidence. Once verified, this site will immediately delete the content suspected of infringement.