1. 程式人生 > >Android 之自定義佈局(繼承控制元件)

Android 之自定義佈局(繼承控制元件)

就是繼承已有的控制元件,建立新控制元件,保留繼承的父控制元件的特性,並且還可以引入新特性。下面就以支援橫向滑動刪除列表項的自定義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="\u5220\u9664"
    android:textColor="#FFFFFF"
    android:textSize="16sp" >

</Button>

2、建立CustomListView類,繼承自ListView,並實現了OnTouchListener和OnGestureListener介面:


package cn.com.tcl.customlistview;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.RelativeLayout;

public class CustomListViewActivity extends ListView implements View.OnTouchListener, GestureDetector.OnGestureListener {

    private final GestureDetector mGestureDetector;
    private View mDeletBtn;
    private ViewGroup mItemLAyout;
    private int mSelecteditem,mlastSelecteditem;
    private boolean isDelectShown;
    private OnDeleteListener mOnDeleteListener;

    public interface OnDeleteListener {
        void onDelete(int index);
    }

    public CustomListViewActivity(Context context, AttributeSet attrs) {
        super(context, attrs);
        mGestureDetector = new GestureDetector(getContext(), this);
        setOnTouchListener(this);
    }

    public void setOnDeleteListener(OnDeleteListener listener) {
        mOnDeleteListener = listener;
    }


    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (isDelectShown) {
            Log.d("haha", "onTouch:---isDelectShown ");
            hideDelete();
            return false;
        } else {
            return mGestureDetector.onTouchEvent(event);
        }
    }

    @Override
    public boolean onDown(MotionEvent e) {
        if(!isDelectShown){
            mSelecteditem = pointToPosition((int) e.getX(),(int) e.getY());
            mlastSelecteditem = mSelecteditem;
            Log.d("haha", "onDown: --->mSelecteditem:"+mSelecteditem);
        }

        return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {
        Log.d("haha", "onShowPress: ");
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        Log.d("haha", "onSingleTapUp: ");
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
      //  Log.d("haha", "onScroll: ");
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {
        Log.d("haha", "onLongPress: ");
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        mSelecteditem = pointToPosition((int) e2.getX(),(int) e2.getY());
        Log.d("haha", "onFling: --->mSelecteditem:"+mSelecteditem);
        if(mlastSelecteditem != mSelecteditem && isDelectShown){
            hideDelete();
        }

        if (!isDelectShown && Math.abs(velocityX) > Math.abs(velocityY)) {
            mDeletBtn = LayoutInflater.from(getContext()).inflate(R.layout.delect_btn, null);


            mDeletBtn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    mItemLAyout.removeView(mDeletBtn);
                    mDeletBtn = null;
                    isDelectShown = false;
                    Log.d("haha", "onClick:--> delete"+mSelecteditem);
                    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(mDeletBtn, params);
            isDelectShown = true;
        }
        return false;
    }
    void hideDelete(){
        mItemLAyout.removeView(mDeletBtn);
        mDeletBtn = null;
        isDelectShown = false;

    }

    public boolean isDelectShown() {
        return isDelectShown;
    }
}
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>
</LinearLayout>
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" />
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();
    }

}

以上程式碼實現le,自定義View。重點:在重寫ListView 時,在類中進行復雜操作。比如點選事件,觸控事件,顯示佈局,更新佈局。在此進行相關的操作~(佈局的變化)然後可以寫一些介面,可供使用的類呼叫!