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

Android 커스텀 View의 세 가지 구현 방법 요약

졸업 프로젝트에서 많이 사용된 사용자 정의 컨트롤러에 대해 언제나 요약하려고 했지만, 오늘 이야기합니다. 이전에 구림 대신에 관련 블로그에 대해 몇 가지 글을 읽었고, 많은 도움이 되었습니다. 이 글에서는 그 중 일부 내용을 참고했습니다.

결론적으로, 사용자 정의 컨트롤러의 구현 방법은 세 가지입니다. 그것은 컴보너트, 드로잉 컨트롤러, 상속 컨트롤러입니다. 아래에서 이 세 가지 방법에 대해 각각 설명하겠습니다.

(1) 컴보너트

컴보너트는 그 이름에서 알 수 있듯이 작은 컨트롤러를 하나의 새로운 컨트롤러로 결합하는 것입니다. 이 작은 컨트롤러들은 대부분 시스템이 제공하는 컨트롤러들입니다. 예를 들어, 많은 애플리케이션에서 일반적으로 사용되는 타이틀 바 컨트롤러는 실제로는 컴보너트를 사용하고 있습니다. 그래서 아래에서 간단한 타이틀 바 사용자 정의 컨트롤러를 통해 컴보너트의 사용법에 대해 설명하겠습니다.

1、Android 프로젝트를 새로 만들고, 사용자 정의 타이틀 바 레이아웃 파일 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="이는 타이틀입니다"
    android:textColor="#ffffff"
    android:textSize="20sp" />
</RelativeLayout>

이 타이틀 바 컨트롤은 상대적으로 간단하게 보입니다. 왼쪽에는 돌아가기 버튼이 있으며, 배경은 사전에 준비된 이미지 back입니다1_64.png, 타이틀 바 중앙에는 타이틀 텍스트가 있습니다。

2TitleView 클래스를 생성하고, RelativeLayout을 상속합니다:

public class TitleView extends RelativeLayout {
  // 돌아가기 버튼 컨트롤
  private Button mLeftBtn;
  // 타이틀 Tv
  private TextView mTitleTv;
  public TitleView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // 레이아웃 로드
    LayoutInflater.from(context).inflate(R.layout.title_bar, this);
    // 컨트롤을 가져옵니다
    mLeftBtn = (Button) findViewById(R.id.left_btn);
    mTitleTv = (TextView) findViewById(R.id.title_tv);
  }
  // 왼쪽 돌아가기 버튼에 사용자 정의 클릭 이벤트를 추가합니다
  public void setLeftButtonListener(OnClickListener listener) {
    mLeftBtn.setOnClickListener(listener);
  }
  // 타이틀 설정 메서드
  public void setTitleText(String title) {
    mTitleTv.setText(title);
  }
}

TitleView에서는 사용자 정의 타이틀 바에 레이아웃을 로드하고, 돌아가기 버튼에 이벤트 리스너를 추가하며, 타이틀 텍스트를 설정하는 메서드를 제공합니다。

3activity_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.TitleView
    android:id="@"+id/title_bar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >
  </com.example.test.TitleView>
</LinearLayout>

4MainActivity에서 사용자 정의 타이틀 바를 가져오고, 돌아가기 버튼에 사용자 정의 클릭 이벤트를 추가합니다:

private TitleView mTitleBar;
     mTitleBar = (TitleView) findViewById(R.id.title_bar);
    mTitleBar.setLeftButtonListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        Toast.makeText(MainActivity.this, "뒤로 가기 버튼을 클릭했습니다", Toast.LENGTH_SHORT)
            .show();
        finish();
      }
    });

5실행 결과는 다음과 같습니다:

   

이렇게 조합을 통해 사용자 정의 타이틀 바를 구현했습니다. 더 많은 조합을 통해 더 복잡한 사용자 정의 컨트롤을 생성할 수 있습니다. 예를 들어, 사용자 정의 검색 표시줄 등.

 (2) 자체 그리기 컨트롤

자체 그리기 컨트롤의 내용은 모두 자체로 그려집니다. View의 onDraw 메서드에서 그리기가 완료됩니다. 아래는 간단한 카운터를 구현하여, 이 컨트롤을 클릭할 때마다 카운트 값이 증가합니다.1그리고 표시합니다.

1CounterView 클래스를 생성하여 View를 상속하고 OnClickListener 인터페이스를 구현합니다:

public class CounterView extends View implements OnClickListener {
  // 페인트 정의
  private Paint mPaint;
  // 문자의 너비와 높이를 얻기 위함
  private Rect mBounds;
  // 카운트 값, 이 컨트롤을 클릭할 때마다 값이 증가합니다1
  private int mCount;
  public CounterView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // 페인트와 Rect 초기화
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mBounds = new Rect();
    // 이 컨트롤의 클릭 이벤트
    setOnClickListener(this);
  }
  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mPaint.setColor(Color.BLUE);
    // 파란색 채우기로된 사각형을 그립니다
    canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
    mPaint.setColor(Color.YELLOW);
    mPaint.setTextSize(50);
    String text = String.valueOf(mCount);
    // 문자의 너비와 높이를 가져옵니다
    mPaint.getTextBounds(text, 0, text.length(), mBounds);
    float textWidth = mBounds.width();
    float textHeight = mBounds.height();
    // 문자열 그리기
    canvas.drawText(text, getWidth(), / 2 - textWidth / 2, getHeight() / 2
        + textHeight / 2, mPaint);
  }
  @Override
  public void onClick(View v) {
    mCount ++;
    // 다시 그리기
    invalidate();
  }
}

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

3실행 결과는 다음과 같습니다:

(3)컨트롤 상속

기존 컨트롤을 상속하고 새 컨트롤을 생성하여 상속된 부모 컨트롤의 특성을 유지하며 새로운 특성을 도입할 수 있습니다. 아래에서는 수평 슬라이딩으로 목록 항목을 삭제할 수 있는 커스텀 ListView의 구현을 설명합니다.

1삭제 버튼 레이아웃 delete_btn.xml을 생성합니다. 이 레이아웃은 수평 슬라이딩 후에 표시됩니다:

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

2CustomListView 클래스를 생성하여 ListView를 상속하고 OnTouchListener 및 OnGestureListener 인터페이스를 구현합니다:

public class CustomListView extends ListView implements OnTouchListener,
    OnGestureListener {
  // 손가락 이동 감지기
  private GestureDetector mGestureDetector;
  // 지우기 이벤트 리스너
  public interface OnDeleteListener {
    void onDelete(int index);
  }
  private OnDeleteListener mOnDeleteListener;
  // 지우기 버튼
  private View mDeleteBtn;
  // 목록 항목 레이아웃
  private ViewGroup mItemLayout;
  // 선택된 목록 항목
  private int mSelectedItem;
  // 현재 지우기 버튼이 표시되었는지
  private boolean isDeleteShown;
  public CustomListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // 갑수 리스너 객체 생성
    mGestureDetector = new GestureDetector(getContext(), this);
    // onTouch 이벤트를 리스닝
    setOnTouchListener(this);
  }
  // 지우기 리스너 이벤트 설정
  public void setOnDeleteListener(OnDeleteListener listener) {
    mOnDeleteListener = listener;
  }
  // 터치 리스너 이벤트
  @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) {
    // 현재 지우기 버튼이 표시되지 않았으며, x 방향 스르르 움직이는 속도가 y 방향 스르르 움직이는 속도보다 크다
    if (!isDeleteShown && Math.abs(velocityX) > Math.abs(velocityY)) {
      mDeleteBtn = LayoutInflater.from(getContext()).inflate(R.layout.delete_btn, null);
          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;
  }
  // 삭제 버튼을 숨기기
  public void hideDelete() {
    mItemLayout.removeView(mDeleteBtn);
    mDeleteBtn = null;
    isDeleteShown = false;
  }
  public boolean isDeleteShown() {
    return isDeleteShown;
  }
  /**
   * 이제 몇 가지 메서드는 이 예제에서 사용되지 않았습니다
   */
  @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);
  }
  // 내용 목록 초기화
  private void initContentList() {
    for (int i = 0; i < 20; i++) {
      contentList.add("내용 항목" + i);
    }
  }
  @Override
  public void onBackPressed() {
    if (mCustomLv.isDeleteShown()) {
      mCustomLv.hideDelete();
      return;
    }
    super.onBackPressed();
  }
}

7실행 결과는 다음과 같습니다:

이것이 이 문서의 모든 내용입니다. 많은 도움이 되길 바랍니다. 또한, 노래 튜토리얼을 많이 지지해 주시기 바랍니다.

고지사항: 이 문서의 내용은 인터넷에서 가져왔으며, 저작권자에게 소유되며, 인터넷 사용자가 자발적으로 기여하고 자체적으로 업로드한 내용입니다. 이 웹사이트는 소유권을 가지지 않으며, 인공 편집 처리를 하지 않았으며, 관련 법적 책임도 부담하지 않습니다. 저작권 위반이 의심되는 내용이 있다면, 이메일을 notice#w로 보내 주시기 바랍니다.3codebox.com(메일을 보내는 경우 #을 @으로 변경하십시오. 신고를 하시고 관련 증거를 제공하시면, 실제로 확인되면 이 사이트는 즉시 위반 내용을 삭제합니다。)

좋아하는 것