Android实现自定义测滑栏

   日期:2020-05-30     浏览:105    评论:0    
核心提示:先上图,这是右侧 这是顶部 左边和下边的都类似,就不放图了,支持简单的手势和代码控制在搞作业的时候需要这样的一个侧边栏功能,能够推挤主屏幕,不是DrawerLayout那种,百度找了好久,只发现一种android近版本中给出的一个Slidingpanelayout的布局,这个布局效果和上图这个类似,唯一不好的就是只有左侧边栏,(或者我没发现有其他设置)于是想到重写这个Slidingpanel...移动开发

先上图,这是右侧                                       

       

  这是顶部 

  

左边和下边的都类似,就不放图了,支持简单的手势和代码控制

在搞作业的时候需要这样的一个侧边栏功能,能够推挤主屏幕,不是DrawerLayout那种,百度找了好久,只发现一种android近版本中给出的一个Slidingpanelayout的布局,这个布局效果和上图这个类似,唯一不好的就是只有左侧边栏,(或者我没发现有其他设置)于是想到重写这个Slidingpanelayout的例子,打开源代码,发现里面写的太高深,看不懂。

如果Slidingpanelayout左侧栏可以满足就不用往下看了,在build.gradle文件导入包的地方加一行:

implementation 'androidx.slidingpanelayout:slidingpanelayout:1.0.0'

直接使用就好,它的布局里只能放两个View,第一个是左侧栏内容,第二个为主页面

源码注释开头:

SlidingPaneLayout provides a horizontal, multi-pane layout for use at the top level of a UI. A left (or first) pane is treated as a content list or browser, subordinate to a primary detail view for displaying content.

SlidingPaneLayout提供了一个水平的、多窗格的布局,用于UI的顶层。左(或第一个)窗格被视为内容列表或浏览器,从属于显示内容的主要详细视图。

百度多次无果,决定自己造一个。

自定义的这个布局比较简陋,只实现了我需要的一点点功能,比如侧边栏展开让主页面变暗色,或者拖拽着边框可以拉拽这样的功能实现比较麻烦,也比较鸡肋,需要的话可以自行尝试添加。话不多说上代码:

在styles.xml文件<resources></resources>中添加如下代码:

<declare-styleable name="MySlidLayout" >
    <attr name="position" format="enum">
        <enum name="top" value="1"/>
        <enum name="left" value="2"/>
        <enum name="right" value="3"/>
        <enum name="bottom" value="4"/>
    </attr>
</declare-styleable>

然后java代码:

import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;

public class MySideBarLayout  extends ViewGroup {
    private int position = 3;//默认右侧栏
    private int move = 0;//记录需要滑动的量
    private boolean isopen = false;//打开状态
    private boolean ishead=false;//判断滑动趋势是否合格
    private float lastX = 0;//记录手指在屏幕中的X
    private float lastY = 0;//记录手指在屏幕中的Y
    private float countmove = 0;//记录累计滑动量X
    //实例化一个监听
   
    public MySideBarLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MySideBarLayout);
        position = typedArray.getInteger(R.styleable.MySideBarLayout_position, 3);
        typedArray.recycle();
    }
    public void setOnChangeListener(OnChangeListener onChangeListener1){
        onChangeListener=onChangeListener1;
    }

    //打开侧边栏
    public void openBar() {
        if (!isopen) {
            onChangeListener.Onchanged(true);
            setMoveAnim(move, getChildAt(0));
            setMoveAnim(move, getChildAt(1));
            isopen = true;
        }
    }
    //关闭侧边栏
    public void closeBar() {
        if (isopen) {
            onChangeListener.Onchanged(false);
            setMoveAnim(0, getChildAt(0));
            setMoveAnim(0, getChildAt(1));
            isopen = false;
        }
    }
    //返回侧边栏的状态
    public boolean isOpen() {
        return isopen;
    }

    
  
    //调用方法启动侧边栏的动画
    private void setMoveAnim(float distance, View view) {
        ObjectAnimator ro;
        if (position == 1 || position == 4) {
            ro = ObjectAnimator.ofFloat(view, "translationY", distance).setDuration(300);
        } else {
            ro = ObjectAnimator.ofFloat(view, "translationX", distance).setDuration(300);
        }
        ro.setInterpolator(new AccelerateDecelerateInterpolator());
        ro.start();
    }
    //手指滑动侧边栏的动画,与上面那个没什么区别,只是时间不一样,手动的快一丢丢
    private void setMoveAnimself(float distance, View view) {
        ObjectAnimator ro;
        if (position == 1 || position == 4) {
            ro = ObjectAnimator.ofFloat(view, "translationY", distance).setDuration(150);
        } else {
            ro = ObjectAnimator.ofFloat(view, "translationX", distance).setDuration(150);
        }
        ro.setInterpolator(new AccelerateDecelerateInterpolator());
        ro.start();
    } 
    //根据子view确定布局本身的大小
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
            int groupWidth = getMaxWidth();
            int groupHeight = getTotalHeight();
            setMeasuredDimension(groupWidth, groupHeight);
        } else if (widthMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(getMaxWidth(), height);
        } else if (heightMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(width, getTotalHeight());
        }
    }
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int pw = r - l;
        int ph = b - t;
        View v1 = getChildAt(0);
        v1.layout(0, 0, pw, ph);
        View v2 = getChildAt(1);
        int vw = v2.getMeasuredWidth();
        int vh = v2.getMeasuredHeight();
        if (position == 1) {
            move = vh;
            v2.layout(0, -vh, pw, 0);
        } else if (position == 2) {
            move = vw;
            v2.layout(-vw, 0, 0, ph);
        } else if (position == 3) {
            move = -vw;
            v2.layout(pw, 0, pw + vw, ph);
        } else if (position == 4) {
            move = -vh;
            v2.layout(0, ph, pw, ph + vh);
        }
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = event.getRawX();
                lastY = event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                float vx = event.getRawX() - lastX;
                float vy = event.getRawY() - lastY;
                if (position == 1) {
                    if(Math.abs(vy)>Math.abs(2*vx)) {
                        if (isopen && vy < 0) {
                            countmove = vy;
                            ishead = true;
                        } else if (!isopen && vy > 0) {
                            countmove = vy;
                            ishead = true;
                        }
                    }
                } else if (position == 2) {
                    if(Math.abs(vx)>Math.abs(2*vy)) {
                        if (isopen && vx < 0) {
                            countmove = vx;
                            ishead = true;
                        } else if (!isopen && vx > 0) {
                            countmove = vx;
                            ishead = true;
                        }
                    }
                } else if (position == 3) {
                    if(Math.abs(vx)>Math.abs(2*vy)) {
                        if (isopen && vx > 0) {
                            countmove = vx;
                            ishead = true;
                        } else if (!isopen && vx < 0) {
                            countmove = vx;
                            ishead = true;
                        }
                    }
                } else if (position == 4) {
                    if(Math.abs(vy)>Math.abs(2*vx)) {
                        if (isopen && vy > 0) {
                            countmove = vy;
                            ishead = true;
                        } else if (!isopen && vy < 0) {
                            countmove = vy;
                            ishead = true;
                        }
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                if (Math.abs(countmove) > Math.abs(move) / 2 && !isopen&&ishead) {
                    isopen = true;
                    ishead=false;
                    onChangeListener.Onchanged(true);
                    setMoveAnimself(move, getChildAt(0));
                    setMoveAnimself(move, getChildAt(1));
                } else if (Math.abs(countmove) > Math.abs(move) / 2 && isopen&&ishead) {
                    isopen = false;
                    ishead=false;
                    onChangeListener.Onchanged(false);
                    setMoveAnimself(0, getChildAt(0));
                    setMoveAnimself(0, getChildAt(1));
                }
                break;
        }
        return true;

    }
    private int getMaxWidth() {
        int count = getChildCount();
        int maxWidth = 0;
        for (int i = 0; i < count; i++) {
            int currentWidth = getChildAt(i).getMeasuredWidth();
            if (maxWidth < currentWidth) {
                maxWidth = currentWidth;
            }
        }
        return maxWidth;
    }

    private int getTotalHeight() {
        int count = getChildCount();
        int totalHeight = 0;
        for (int i = 0; i < count; i++) {
            totalHeight += getChildAt(i).getMeasuredHeight();
        }
        return totalHeight;
    }
    private OnChangeListener onChangeListener=new OnChangeListener() {
        @Override
        public void Onchanged(boolean status) {

        }
    };

    public  interface OnChangeListener{
        void Onchanged(boolean status);
    }
}

使用方法:第一个view为主页面,第二个为侧页面。

在<MySideBarLayout/>中调用

app:position="top"

提供四个选项 : top , left , right , bottom    

<包名.MySideBarLayout
    android:id="@+id/sidelayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:position="top"
    >
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#00cc66">

    </RelativeLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:background="#ffff33">
     
    </LinearLayout>



</包名.MySideBarLayout>

java 代码中我实现了几个简单的方法:

openBar()打开侧栏

closeBar()关闭侧栏

isOpen()  获取侧边栏的状态

setOnChangeListener(OnChangeListener onChangeListener1)设置侧边栏变化监听

这里注意监听名,MySideBarLayout.OnChangeListener()是我在包内自定义的监听

mysidebarlayout.setOnChangeListener(new MySideBarLayout.OnChangeListener() {
    @Override
    public void Onchanged(boolean status) {
        if(status){
            textview.setText("侧边栏已打开");
        }else{
            textview.setText("侧边栏已关闭");
        }
    }
});

就这么简单就OK了,如果需要在这个布局里同时能滑动四个侧边栏,也可以实现的,重写这个onlayout........需要的话自行解决吧,东西比较简陋,有什么问题可以留言建议,我再调整调整,一起学习学习

 

 

 

 

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
更多>相关资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服