English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Resumen de tres métodos de implementación de View personalizada en Android

Se utilizan muchos componentes personalizados en el proyecto de la tesis, y siempre he planeado resumir la forma de implementar componentes personalizados. Hoy en día, voy a resumir. Antes de eso, aprendí algunos artículos de blog de la gran figura Guo Lin, y siento que he aprendido mucho, y este artículo se refiere a algunos de los contenidos.

En resumen, la implementación de componentes personalizados tiene tres métodos, respectivamente: componentes combinados, componentes dibujados y componentes heredados. A continuación, se presentarán estos tres métodos respectivamente.

(一)组件组合

Los componentes combinados, como su nombre indica, consisten en combinar varios componentes pequeños para formar un nuevo componente, y estos pequeños componentes son muchos componentes del sistema. Por ejemplo, los componentes de la barra de título utilizados en muchas aplicaciones son componentes combinados. A continuación, se explicará el uso de los componentes combinados a través de la implementación de un componente personalizado de barra de título simple.

1、Crear un proyecto de Android nuevo, crear un archivo de diseño personalizado de la barra de título 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="Este es el título"
    android:textColor="#ffffff"
    android:textSize="20sp" />
</RelativeLayout>

Visible que este controlador de barra de título es bastante simple, en la izquierda hay un botón de regreso y el fondo es una imagen preparada anteriormente back1_64.png, el texto del título está en el centro de la barra de título.

2Crear una clase TitleView, que hereda de RelativeLayout:

public class TitleView extends RelativeLayout {
  // Controlador del botón de regreso
  private Button mLeftBtn;
  // Texto de título
  private TextView mTitleTv;
  public TitleView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // Cargar el diseño
    LayoutInflater.from(context).inflate(R.layout.title_bar, this);
    // Obtener los controladores
    mLeftBtn = (Button) findViewById(R.id.left_btn);
    mTitleTv = (TextView) findViewById(R.id.title_tv);
  }
  // Agregar un evento de clic personalizado al botón de regreso izquierdo
  public void setLeftButtonListener(OnClickListener listener) {
    mLeftBtn.setOnClickListener(listener);
  }
  // Método para establecer el título
  public void setTitleText(String title) {
    mTitleTv.setText(title);
  }
}

En TitleView, principalmente se carga el diseño de la barra de título personalizada, se agrega un método de escucha de eventos al botón de regreso y se proporciona un método para establecer el texto del título.

3En activity_main.xml, importar la barra de título personalizada:

<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>

4En MainActivity, obtener la barra de título personalizada y agregar un evento de clic personalizado al botón de regreso:

private TitleView mTitleBar;
     mTitleBar = (TitleView) findViewById(R.id.title_bar);
    mTitleBar.setLeftButtonListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Toast.makeText(MainActivity.this, "Se hizo clic en el botón de regreso", Toast.LENGTH_SHORT)
            .show();
        finish();
      }
    });

5El efecto de ejecución es el siguiente:

   

De esta manera, se ha implementado un título personalizado de combinación, realmente, mediante más combinaciones, se pueden crear controles personalizados más complejos, como una barra de búsqueda personalizada, etc.

 (II) Controlador de dibujo autónomo

Los controles dibujados de manera autónoma son todos dibujados por sí mismos, se completan en el método onDraw de View. A continuación, se realiza un simple contador, cada vez que se hace clic en él, el valor de cuenta se suma1Y mostrar.

1、Crear la clase CounterView, que hereda de View e implementa la interfaz OnClickListener:

public class CounterView extends View implements OnClickListener {
  // Definir pluma
  private Paint mPaint;
  // Se utiliza para obtener el ancho y la altura del texto
  private Rect mBounds;
  // El valor de cuenta, cada vez que se hace clic en este controlador, su valor aumenta1
  private int mCount;
  public CounterView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // Inicializar pluma y Rect
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mBounds = new Rect();
    // El evento de clic de este controlador
    setOnClickListener(this);
  }
  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mPaint.setColor(Color.BLUE);
    // Dibujar un rectángulo relleno de azul
    canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
    mPaint.setColor(Color.YELLOW);
    mPaint.setTextSize(50);
    String text = String.valueOf(mCount);
    // Obtener el ancho y alto del texto
    mPaint.getTextBounds(text, 0, text.length(), mBounds);
    float textWidth = mBounds.width();
    float textHeight = mBounds.height();
    // Dibujar cadena
    canvas.drawText(text, getWidth() / 2 - textWidth / 2, getHeight() / 2
        + textHeight / 2, mPaint);
  }
  @Override
  public void onClick(View v) {
    mCount ++;
    // Redibujar
    invalidate();
  }
}

2Introducir este diseño personalizado en activity_main.xml:

<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>

3El efecto de ejecución es el siguiente:

(Tres) Heredar controles

Es heredar de un control existente, crear un nuevo control, mantener las características del control heredado del padre y, además, introducir nuevas características. A continuación, se presenta una implementación de CustomListView que admite la eliminación de elementos de lista deslizando horizontalmente.

1Crear el diseño de botón de eliminación delete_btn.xml, que se muestra después de deslizar horizontalmente una entrada de lista:

<?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="eliminar"
  android:textColor="#FFFFFF"
  android:textSize="16sp" >
</Button>

2Crear la clase CustomListView que hereda de ListView e implementa las interfaces OnTouchListener y OnGestureListener:

public class CustomListView extends ListView implements OnTouchListener,
    OnGestureListener {
  // Detector de acción de gestos
  private GestureDetector mGestureDetector;
  // escucha de eventos de eliminación
  public interface OnDeleteListener {
    void onDelete(int index);
  }
  private OnDeleteListener mOnDeleteListener;
  // botón de eliminación
  private View mDeleteBtn;
  // diseño de elemento de lista
  private ViewGroup mItemLayout;
  // elemento de lista seleccionado
  private int mSelectedItem;
  // Si el botón de eliminación actual se muestra
  private boolean isDeleteShown;
  public CustomListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // Crear objeto de escucha de gestos
    mGestureDetector = new GestureDetector(getContext(), this);
    // escuchar evento onTouch
    setOnTouchListener(this);
  }
  // establecer evento de escucha de eliminación
  public void setOnDeleteListener(OnDeleteListener listener) {
    mOnDeleteListener = listener;
  }
  // evento de escucha de toque
  @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) {
    // Si el botón de eliminación actual no se muestra y la velocidad de deslizamiento en el eje X es mayor que la velocidad de deslizamiento en el eje Y
    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;
  }
  // ocultar el botón de eliminación
  public void hideDelete() {
    mItemLayout.removeView(mDeleteBtn);
    mDeleteBtn = null;
    isDeleteShown = false;
  }
  public boolean isDeleteShown() {
    return isDeleteShown;
  }
  /**
   * las siguientes métodos no se utilizan en este ejemplo
   */
  @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) {
  }
}

3、定义列表项布局custom_listview_item.xml,它的结构很简单,只包含了一个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>

4、定义适配器类CustomListViewAdapter,继承自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;
  }
}

5、在activity_main.xml中引入自定义的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>

6、在MainActivity中对列表进行初始化、设置列表项删除按钮点击事件等处理:

public class MainActivity extends Activity {
  // 自定义Lv
  private CustomListView mCustomLv;
  // 自定义适配器
  private CustomListViewAdapter mAdapter;
  // 内容列表
  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);
  }
  // Inicializar lista de contenido
  private void initContentList() {
    for (int i = 0; i < 20; i++) {
      contentList.add("elemento de contenido" + i);
    }
  }
  @Override
  public void onBackPressed() {
    if (mCustomLv.isDeleteShown()) {
      mCustomLv.hideDelete();
      return;
    }
    super.onBackPressed();
  }
}

7El efecto de ejecución es el siguiente:

Esto es todo el contenido del artículo, espero que sea útil para su aprendizaje y que todos apoyen el tutorial de alarido.

Aviso: Este artículo se ha redactado en línea, el copyright pertenece al propietario original, el contenido ha sido contribuido y subido por los usuarios de Internet, este sitio web no posee los derechos de propiedad, no se ha procesado editorialmente y no asume ninguna responsabilidad legal. Si encuentra contenido sospechoso de infracción de derechos de autor, por favor envíe un correo electrónico a: notice#w proporcionando evidencia relevante.3Declaración: El contenido de este artículo se ha obtenido de la red, pertenece al propietario original, el contenido se ha contribuido y subido por los usuarios de Internet, este sitio web no posee los derechos de propiedad, no se ha procesado editorialmente y no asume ninguna responsabilidad legal. Si encuentra contenido sospechoso de infracción de derechos de autor, por favor envíe un correo electrónico a: notice#w proporcionando evidencia relevante, una vez confirmado, este sitio eliminará inmediatamente el contenido sospechoso de infracción.

Te gustaría que te gustara