Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 安卓開發之自定義控件TipView仿QQ長按後的提示窗口

安卓開發之自定義控件TipView仿QQ長按後的提示窗口

編輯:關於Android編程


先上效果圖:

這裡寫圖片描述

之前用手機QQ時,一直很覺得這個窗口提示挺不錯的,今天將它大概地實現了一遍。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPsrXz8jKx6O6zOHKvrSwv9q1xMj9vcfPwrHqyse/ydLUuMSx5M671sO1xKOsyLu687Swv9rW0NPQuty24NChtcRpdGVto6xpdGVtsbu147v3yrG74c/Uyr6z9rK7zay1xNHVyaujrDwvcD4NCjxwPs2syrHI/b3Hz8Kx6rXE0dXJq9Kyy+bXxbjEseShozwvcD4NCjxwPsi7uvPKx6O6zOHKvrSwv9q1xGl0ZW3Dx7vhuPm+3bSryOu1xNf4serKtc/Wz/LJz8/Uyr678s/yz8LP1Mq+oaM8L3A+DQo8aDIgaWQ9"一對tipview定義一些成員變量">一、對TipView定義一些成員變量

// 一些狀態變量
private static final int STATUS_DOWN = 1;
private static final int STATUS_UP = 2;
// 初始窗口的Item顯示在上方
private int mStatus = STATUS_UP;


// Item之間的分隔線的顏色
private int mSeparateLineColor ;

// 窗口邊上兩個方塊的邊角半徑大小
private int mCorner = dip2px(6);

private Paint mPaint; // 畫方塊和文字的畫筆
private Paint doPaint; // 畫三角下標的畫筆

private Path mPath; // 繪制的路徑

private int mBorderMargin = dip2px(5); // 提示窗口與屏幕(根布局)的最小距離
private int mItemWidth = dip2px(50); // 窗口Item的寬度
private int mItemHeight = dip2px(48); // 窗口Item的高度
private int mTriangleTop = dip2px(50); // 三角下標的頂點
private int mHalfTriangleWidth = dip2px(6); // 三角小標的半寬
private int mItemBorder; // 三角小標與窗口Item的臨界
private int realLeft; // 窗口的left值

private List mItemList = new ArrayList<>(); // 存儲每個Item的信息
private List mItemRectList = new ArrayList<>(); // 存儲每個方塊的信息


private OnItemClickListener onItemClickListener; // Item點擊接口
private int choose = -1; // 是否有Item被按下,是為Item的序號,否為-1

// 外界傳入的點擊坐標x、y
private int x;
private int y;

二、TipView的初始化

TipView的構造方法:

public TipView(Context context, ViewGroup rootView,int x,int y,List mItemList) {
    super(context);

    this.x = x; // 設置傳入過來的x軸坐標
    this.y = y;  // 設置傳入過來的y軸坐標
    // x和y決定了三角下標的位置

    initPaint(); // 初始化畫筆
    setTipItemList(mItemList); // 初始化Item集合,並對Item的字符串長度進行處理
    //【當字符串過長時,使用後端省略處理:“xxx...”】
    addView(rootView); // 將TipView實例添加到傳入的rootView中。
    // 注意:rootView需要FrameLayout/RelativeLayout或其子類實例

    initView(); // 根據傳入的點擊坐標x、y進行狀態判斷和最左位置的處理 
}

initView()的具體實現:主要對臨界情況的一些值得處理

private void initView() {

    // 獲取屏幕寬度
    int mScreenWidth = getResources().getDisplayMetrics().widthPixels;

    // 當點擊事件的縱坐標y比較小時(點擊的位置比較上面)
    if (y/2 mScreenWidth) {
        // 跑出屏幕右邊的話,則減去溢出的寬度,再減去距離值
        realLeft -= realLeft + (mItemWidth*mItemList.size())-mScreenWidth+mBorderMargin;
        // 防止三角下標與方塊分離
        if(x+mCorner>=realLeft+mItemWidth*mItemList.size()) 
            x =  realLeft+mItemWidth*mItemList.size()-mCorner*2;
    }
    // 沒有對窗口左右邊都超出的情況做處理,大家有沒有好的解決方案?

}

三、TipView的繪制

首先繪制圖層為透明,再根據判斷得來的狀態繪制窗口。

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    drawBackground(canvas);
    switch (mStatus) {
        case STATUS_DOWN:
            drawItemDown(canvas);
            break;
        case STATUS_UP:
            drawItemUp(canvas);
            break;
        default:
            break;
    }
}

具體繪制各個窗口方塊的代碼太長不便貼出,可參考源碼及其注釋。

大致的流程就是

a. 繪制最左方塊、最右方塊和中間方塊
b. 根據方塊是否被點擊而更換不同的顏色來繪制方塊
c. 繪制分隔線

四、TipView中的Item點擊事件的監聽

設計一個監聽器接口:

public interface OnItemClickListener {
    // 設計兩個參數
    void onItemClick(String name,int position);
    void dismiss();
}

覆寫TipView的onTouchEvent方法:

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            for (int i = 0; i < mItemRectList.size(); i++) {
                if (onItemClickListener != null && isPointInRect(new PointF(event.getX(), event.getY()), mItemRectList.get(i))) {
                   // 被按下時,choose值為當前方塊Item序號
                    choose = i;
                    // 更新視圖
                    invalidate(mItemRectList.get(i));
                }
            }
            return true;
        case MotionEvent.ACTION_UP:
            for (int i = 0; i < mItemRectList.size(); i++) {
                if (onItemClickListener != null && isPointInRect(new PointF(event.getX(), event.getY()), mItemRectList.get(i))) {
                    // 觸發方法,傳入兩個參數
                    onItemClickListener.onItemClick(mItemList.get(i).getTitle(),i);
                    choose = -1;
                }
            }

            if (onItemClickListener != null) {
                onItemClickListener.dismiss(); // 觸發方法
            }

            removeView(); // 移除TipView

            return true;
    }
    return true;
}

五、以Build模式為設計模式:

public static class Builder {

    // TipView中一些重要的成員變量
    private OnItemClickListener onItemClickListener;
    private Context mContext;

    private ViewGroup mRootView; 
    private List mTipItemList = new ArrayList<>();
    private int mSeparateLineColor = Color.WHITE;
    private int x ,y;

    public Builder(Context context, ViewGroup rootView,int x,int y) {
        mContext = context;
        mRootView = rootView;
        this.x = x;
        this.y = y;
    }

    public Builder addItem(TipItem tipItem) {
        mTipItemList.add(tipItem);
        return this;
    }

    public Builder addItems(List list) {
        mTipItemList.addAll(list);
        return this;
    }

    public Builder setSeparateLineColor(int color) {
        mSeparateLineColor = color;
        return this;
    }

    public Builder setOnItemClickListener(OnItemClickListener onItemClickListener){
        this.onItemClickListener = onItemClickListener;
        return this;
    }

    // 創建TipView實例
    public TipView create() {
        TipView flipShare = new TipView(mContext, mRootView,x,y,mTipItemList);
        flipShare.setOnItemClickListener(onItemClickListener);
        flipShare.setSeparateLineColor(mSeparateLineColor);
        return flipShare;
    }

}

六、使用示例:

創建TipView實例時,需要傳入控件被點擊或長按時的位置坐標。

使用注意:傳給rootView的參數需要FrameLayout / RelativeLayout或其子類實例,這樣TipView對象才可以懸浮地顯示出來。

public class MainActivity extends AppCompatActivity {

    private Button button0;
    private RelativeLayout rl;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button0 = (Button) findViewById(R.id.button0);
        rl = (RelativeLayout) findViewById(R.id.activity_main);

        button0.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int x = 0;int y = 0;
                if(event.getAction()==MotionEvent.ACTION_UP){
                    // 獲取點擊位置
                    x= (int) event.getX();y = (int) event.getY();
                    Log.i("zz",x+"  "+y);
                    // 傳入視圖上的坐標
                    TipView share = new TipView.Builder(MainActivity.this,rl,x+v.getLeft(),y+v.getTop())
                            .addItem(new TipItem("復制復制"))
                            .addItem(new TipItem("粘貼"))
                            .addItem(new TipItem("刪除"))
                            .addItem(new TipItem("收藏"))
                            .addItem(new TipItem("轉發"))
                            .addItem(new TipItem("更多"))
                            .setOnItemClickListener(new TipView.OnItemClickListener() {
                                @Override
                                public void onItemClick(String str,int a) {
                                    Toast.makeText(MainActivity.this,str,Toast.LENGTH_SHORT).show();
                                }

                                @Override
                                public void dismiss() {

                                }
                            })
                            .create();
                }
                return true;
            }
        });


    }


}

效果圖Demo:Github

參考:

https://github.com/JeasonWong/FlipShare

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved