仿微信侧滑菜单slidemenu

直接上代码 

slidemenu

package com.example.myapplication.customview;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.TextView;

import com.example.myapplication.R;

public class SlideMenu extends ViewGroup implements View.OnClickListener {
    private static final String TAG = "SlideMenu";
    private int function;
    private View contentView;
    private LinearLayout functionView;
    private Scroller scroller;

    float downX = 0;
    float downY = 0;


    public boolean isOpen() {
        return isOpen;
    }

    private boolean isOpen = false;

    private Direction direction = Direction.NONE;
    private float interceptDownX;

    enum Direction {
        LEFT, RIGHT, NONE
    }

    public SlideMenu(Context context) {
        this(context, null);
    }

    public SlideMenu(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SlideMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 1、添加属性

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlideMenu);
        function = a.getInt(R.styleable.SlideMenu_function, 0);
        a.recycle();


    }


    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        ///2、将View加入进来
        contentView = getChildAt(0);
        functionView = (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.slide_item_layout, this, false);
        addView(functionView);
        scroller = new Scroller(getContext());
        initFunctionView();
        Log.d(TAG, "get child count===> " + getChildCount());

    }

    private void initFunctionView() {
        TextView read = functionView.findViewById(R.id.read);
        TextView delete = functionView.findViewById(R.id.delete);
        TextView top = functionView.findViewById(R.id.top);

        delete.setOnClickListener(this);
        read.setOnClickListener(this);
        top.setOnClickListener(this);

        initSlideViewVisible(delete, read, top);

    }


    private void initSlideViewVisible(TextView delete, TextView read, TextView top) {
        final int TOP = 0x03;
        final int DELETE = 0x30;
        final int READ = 0x50;
        final int TOP_DELETE = TOP | DELETE;
        final int TOP_READ = TOP | READ;
        final int READ_DELETE = READ | DELETE;
        final int TOP_READ_DELETE = TOP | READ | DELETE;

        switch (function) {
            case DELETE:
                delete.setVisibility(VISIBLE);
                break;
            case READ:
                read.setVisibility(VISIBLE);
                break;
            case TOP:
                top.setVisibility(VISIBLE);
                break;
            case TOP_DELETE:
                top.setVisibility(VISIBLE);
                delete.setVisibility(VISIBLE);

                break;
            case TOP_READ:
                top.setVisibility(VISIBLE);
                read.setVisibility(VISIBLE);

                break;
            case READ_DELETE:
                read.setVisibility(VISIBLE);
                delete.setVisibility(VISIBLE);
                break;
            case TOP_READ_DELETE:
                top.setVisibility(VISIBLE);
                read.setVisibility(VISIBLE);
                delete.setVisibility(VISIBLE);
                break;
        }

    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int parentHeightSizeSpec = MeasureSpec.getSize(heightMeasureSpec);

        //3、测量第一个孩子

        LayoutParams layoutParams = contentView.getLayoutParams();
        int height = layoutParams.height;

        int heightSpec;
        if (height == LayoutParams.MATCH_PARENT) {
            heightSpec = MeasureSpec.makeMeasureSpec(parentHeightSizeSpec, MeasureSpec.AT_MOST);
        } else if (height == MeasureSpec.EXACTLY) {
            heightSpec = MeasureSpec.makeMeasureSpec(parentHeightSizeSpec, MeasureSpec.EXACTLY);
        } else {
            heightSpec = MeasureSpec.makeMeasureSpec(parentHeightSizeSpec, MeasureSpec.AT_MOST);
        }

        measureChild(contentView, widthMeasureSpec, heightSpec);

        //4、测量第二个孩子

        int measuredHeight = contentView.getMeasuredHeight();

        // 第二个孩子的宽度为最大宽度的3/4
        // 根据具体的孩子来显示具体的宽度

        int visibleCount = 0;
        for (int i = 0; i < functionView.getChildCount(); i++) {
            if (functionView.getChildAt(i).getVisibility() == View.VISIBLE) {
                visibleCount++;
            }
        }
        Log.d(TAG, "child count ==== >" + visibleCount);

        int functionSize = widthMeasureSpec * visibleCount / 4;

        int functionWidth = MeasureSpec.makeMeasureSpec(functionSize, MeasureSpec.EXACTLY);
        int functionHeight = MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY);

        measureChild(functionView, functionWidth, functionHeight);

    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        // 5、布局第一个孩子
        int contentLeft = 0;
        int contentTop = 0;
        int contentRight = contentLeft + contentView.getMeasuredWidth();
        int contentBottom = contentView.getMeasuredHeight();
        contentView.layout(contentLeft, contentTop, contentRight, contentBottom);


        int functionTop = 0;
        int functionRight = contentRight + functionView.getMeasuredWidth();

        functionView.layout(contentRight, functionTop, functionRight, contentBottom);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        //6、计算按下的位置与移动的位置移动当前的视图
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                downY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:

                float moveX = event.getX();
                float moveY = event.getY();

                int dx = (int) (moveX - downX);
                if (dx > 0) {
                    direction = Direction.RIGHT;
                } else if (dx < 0) {
                    direction = Direction.LEFT;
                }

                float hasBeenScrolled = getScrollX();

                int resultX = (int) (hasBeenScrolled - dx);
                if (resultX <= 0) {
                    scrollTo(0, 0);
                } else if (resultX > functionView.getMeasuredWidth()) {
                    scrollTo(functionView.getMeasuredWidth(), 0);
                } else {
                    scrollBy(-dx, 0);
                }
                downX = moveX;
                downY = moveY;
                break;
            case MotionEvent.ACTION_UP:
                int scrollX = getScrollX();
                Log.d(TAG, "scroll > >" + scrollX);
                if (isOpen) {
                    //若是打开的
                    if (direction == Direction.LEFT) {
                        open();
                    } else if (direction == Direction.RIGHT) {

                        if (scrollX <= functionView.getMeasuredWidth() * 4 / 5) {
                            close();
                        } else {
                            open();
                        }
                    }
                } else {
                    //默认是关闭的
                    if (direction == Direction.LEFT) {
                        //判断当前滑动的距离
                        if (scrollX >= functionView.getMeasuredWidth() / 5) {
                            open();
                        } else {
                            close();
                        }

                    } else if (direction == Direction.RIGHT) {
                        close();
                    }

                }

                break;
        }

        return true;

    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        //事件冲突

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                interceptDownX = ev.getX();
                float interceptDownY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float interceptMoveX = ev.getX();
                float interceptMoveY = ev.getY();
                int intercept = (int) (interceptMoveX - interceptDownX);
                if (Math.abs(intercept) > 0) {
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }


        return super.onInterceptTouchEvent(ev);

    }

    private void open() {
        scroller.startScroll(getScrollX(), 0, functionView.getMeasuredWidth() - getScrollX(), 0, 500);
        isOpen = true;
        invalidate();
    }


    private void close() {
        scroller.startScroll(getScrollX(), 0, -getScrollX(), 0, 500);
        isOpen = false;
        invalidate();
    }

    @Override
    public void onClick(View v) {
        close();
        switch (v.getId()) {
            case R.id.read:
                onItemClickListener.onReadClick();
                break;
            case R.id.delete:
                onItemClickListener.onDeleteClick();
                break;
            case R.id.top:
                onItemClickListener.onTopClick();
                break;
        }
    }

    @Override
    public void computeScroll() {
        super.computeScroll();

        if (scroller.computeScrollOffset()) {
            int currX = scroller.getCurrX();
            scrollTo(currX, 0);
            invalidate();
        }
    }


    // 通过接口将事件传递出去
    private onItemClickListener onItemClickListener;

    public void setOnItemClickListener(SlideMenu.onItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }

    public interface onItemClickListener {
        void onDeleteClick();

        void onReadClick();

        void onTopClick();
    }
}

属性 

<declare-styleable name="SlideMenu">
    <attr name="function" format="flags">
        <flag name="delete" value="0x30" />
        <flag name="read" value="0x50" />
        <flag name="top" value="0x03" />
    </attr>
</declare-styleable>

 

布局

activity_main

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <com.example.myapplication.customview.SlideMenu
        android:id="@+id/slide_menu"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:function="top|delete">

        <TextView
            android:id="@+id/content_tv"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:background="#dddddd"
            android:gravity="center"
            android:text="群成员"
            android:textColor="#000"
            android:textSize="20sp" />
    </com.example.myapplication.customview.SlideMenu>

</LinearLayout>

slide_item_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/read"
        android:layout_width="0dp"
        android:visibility="gone"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#008800"
        android:gravity="center"
        android:text="已读"
        android:textColor="#fff"
        android:textSize="20dp" />

    <TextView
        android:id="@+id/top"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#666666"
        android:visibility="gone"
        android:gravity="center"
        android:text="置顶"
        android:textColor="#fff"
        android:textSize="20dp" />

    <TextView
        android:visibility="gone"
        android:id="@+id/delete"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#ff0000"
        android:gravity="center"
        android:text="删除"
        android:textColor="#fff"
        android:textSize="20dp" />
</LinearLayout>

MainActivity

 

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toast;

import com.example.myapplication.customview.FlowLayout;
import com.example.myapplication.customview.SlideMenu;
import com.example.myapplication.customview.TextBanner;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SlideMenu slideMenu = findViewById(R.id.slide_menu);
        slideMenu.setOnItemClickListener(new SlideMenu.onItemClickListener() {
            @Override
            public void onDeleteClick() {
                Log.d(TAG, "ON DELETE");
            }

            @Override
            public void onReadClick() {
                Log.d(TAG, "ON READ");
            }

            @Override
            public void onTopClick() {
                Log.d(TAG, "ON TOP");

            }
        });
    }
}

效果图  

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值