Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android---自定義左滑右滑菜單

android---自定義左滑右滑菜單

編輯:關於Android編程

沒有使用第三方類庫,純代碼定制.主要用到的知識如下,

我們知道,不管是自定義View還是系統提供的TextView這些,它們都必須放置在LinearLayout等一些ViewGroup中,因此理論上我們可以很好的理解onMeasure(),onLayout(),onDraw()這三個函數:1.View本身大小多少,這由onMeasure()決定;2.View在ViewGroup中的位置如何,這由onLayout()決定;3.繪制View,onDraw()定義了如何繪制這個View。

一個MeasureSpec封裝了父布局傳遞給子布局的布局要求,每個MeasureSpec代表了一組寬度和高度的要求。一個MeasureSpec由大小和模式組成。它有三種模式:UNSPECIFIED(未指定),父元素部隊自元素施加任何束縛,子元素可以得到任意想要的大小;EXACTLY(完全),父元素決定自元素的確切大小,子元素將被限定在給定的邊界裡而忽略它本身大小;AT_MOST(至多),子元素至多達到指定大小的值。

  它常用的三個函數:

  1.static int getMode(int measureSpec):根據提供的測量值(格式)提取模式(上述三個模式之一)

  2.static int getSize(int measureSpec):根據提供的測量值(格式)提取大小值(這個大小也就是我們通常所說的大小)

  3.static int makeMeasureSpec(int size,int mode):根據提供的大小值和模式創建一個測量值(格式)

public static final int ACTION_DOWN = 0; // 按下事件
public static final int ACTION_UP = 1; // 抬起事件
public static final int ACTION_MOVE = 2; // 手勢移動事件
public static final int ACTION_CANCEL = 3; // 取消

還有觸摸事件,滾動的實現等,代碼注釋很詳細

public class MainUI extends RelativeLayout {

    private Context context;
    private FrameLayout middleMenu,leftMenu,rightMenu;
    //設置模版
    private FrameLayout middlemask;
    private Scroller scroller;

    //屬於自定義view,這裡就需要用到這兩個構造函數
    public MainUI(Context context){
        super(context);
        inintView(context);
    }

    public MainUI(Context context, AttributeSet attrs) {
        super(context, attrs);
        inintView(context);
    }
    //初始化各種變量
    public void inintView(Context context){
        this.context = context;
        //然後我們需要三個界面布局,這裡用framelayout來承載
        //設置滑動的是當前content和滑動樣式
        scroller = new Scroller(context,new DecelerateInterpolator());
        leftMenu = new FrameLayout(context);
        middleMenu = new FrameLayout(context);
        rightMenu = new FrameLayout(context);
        middlemask = new FrameLayout(context);
        //為了區分給每個部分設置顏色
        leftMenu.setBackgroundColor(Color.RED);
        middleMenu.setBackgroundColor(Color.BLUE);
        rightMenu.setBackgroundColor(Color.GREEN);
        middlemask.setBackgroundColor(Color.GRAY);
        middlemask.setAlpha(0);
        //添加到當前布局
        addView(leftMenu);
        addView(middleMenu);
        addView(rightMenu);
        addView(middlemask);

        //接下來要測量寬度,好用來給這三個部分分別設置寬度,放在onmeasure中
    }

    /**這個方法決定view本身的大小
     * 這裡的兩個參數分別是屏幕的寬和高
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //中間的寬度正好是整個屏幕
        middleMenu.measure(widthMeasureSpec, heightMeasureSpec);
        middlemask.measure(widthMeasureSpec, heightMeasureSpec);
        //旁邊的則最多為屏幕的80%
        int realWidth = MeasureSpec.getSize(widthMeasureSpec);
        int tempWidthMeasure = MeasureSpec.makeMeasureSpec(
                (int)(realWidth*0.8f),MeasureSpec.EXACTLY);
        leftMenu.measure(tempWidthMeasure, heightMeasureSpec);
        rightMenu.measure(tempWidthMeasure, heightMeasureSpec);
    }

    /**這個方法決定view在layout中的位置
     *四個參數對應屏幕 左上右下
     * @param changed
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        //中間菜單是中間的屏幕
        middleMenu.layout(l, t, r, b);
        middlemask.layout(l, t, r, b);
        //左邊的菜單則左邊界要擴充
        leftMenu.layout(l - leftMenu.getMeasuredWidth(), t, r, b);
        //右邊界左右都要設置
        rightMenu.layout(
                l + middleMenu.getMeasuredWidth(),
                t,
                l + middleMenu.getMeasuredWidth()
                        + rightMenu.getMeasuredWidth(), b);
        //接下來添加滑動事件
    }


    private boolean isTsetCompete;
    /**
     * 處理相應的觸摸事件
     * @param ev
     * @return
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        if (!isTsetCompete){
            getEventType(ev);
            return true;
        }
        //如果是左右滑動
        if (isleftrightmove){
            switch(ev.getActionMasked()){
                case MotionEvent.ACTION_MOVE:
                    //得到滑動距離
                    int currScrollX = getScrollX();
                    //得到移動距離
                    int dis_x = (int)(ev.getX() -point.x);
                    //他倆差值肯定在20之間
                    int expectX = -dis_x +currScrollX;
                    int finalx=0;
                    if (expectX<0){
                        //右滑距離
                        finalx = Math.max(expectX,-leftMenu.getMeasuredWidth());
                    }else{
                        //左滑距離
                        finalx = Math.min(expectX,rightMenu.getMeasuredWidth());
                    }
                    scrollTo(finalx,0);
                    point.x = (int) ev.getX();
                    break;
                //下面判斷繼續滑動或者手指離開屏幕
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    //判斷如果滑動距離大於一半則自動滑動出來,否則滑動回去
                    currScrollX = getScrollX();
                    if (Math.abs(currScrollX) > leftMenu.getMeasuredWidth() >>1) {
                        if (currScrollX < 0) {
                            scroller.startScroll(currScrollX, 0, -leftMenu.getMeasuredWidth() - currScrollX, 0);
                        }else {
                            scroller.startScroll(currScrollX,0,leftMenu.getMeasuredWidth()-currScrollX,0);
                        }
                    }else{
                        scroller.startScroll(currScrollX,0,-currScrollX,0);
                    }
                    //用於屏幕刷新
                    invalidate();
                    isleftrightmove = false;
                    isTsetCompete = false;
                    break;
            }
        }

        return super.dispatchTouchEvent(ev);
    }

    /**
     * 在滑動改變距離的同時改變透明度,這種方式很好,因為會先調用父類的方法,所以不會影響到原來程序的運行
     * @param x
     * @param y
     */
    @Override
    public void scrollTo(int x, int y) {
        super.scrollTo(x, y);
        int cruX = Math.abs(getScrollX());
        float fo = cruX / (float)middleMenu.getMeasuredWidth();
        middlemask.setAlpha(fo);
    }

    /**
     * 滾動條的回調方法
     */
    @Override
    public void computeScroll() {
        super.computeScroll();
        if (!scroller.computeScrollOffset()){
            return;
        }
        int tempX = scroller.getCurrX();
        scrollTo(tempX,0);
    }

    private Point point = new Point();
    private static final int TSET_DIS = 20;
    private boolean isleftrightmove;
    /**
     * 用於判斷觸摸事件類型的函數
     * @param ev
     */
    private void getEventType(MotionEvent ev) {
        switch(ev.getActionMasked()){
            case MotionEvent.ACTION_DOWN:
                //得到當前坐標
                point.x = (int) ev.getX();
                point.y = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                int dX = Math.abs((int)ev.getX()-point.x);
                int dY = Math.abs((int)ev.getY()-point.y);
                //左右滑動
                if (dX >=TSET_DIS && dX>dY){
                    isleftrightmove = true;
                    isTsetCompete = true;
                    //為了滑動後可以再次滑動
                    point.x = (int) ev.getX();
                    point.y = (int) ev.getY();
                }else if (dY>=TSET_DIS&&dY>dX){
                    isleftrightmove = false;
                    isTsetCompete = false;
                    point.x = (int) ev.getX();
                    point.y = (int) ev.getY();
                }

                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:

                break;
        }
    }
}

這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

 

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