侧拉新闻菜单

功能描述

菜单分左右两侧,整体可以滑动,效果如下
左侧菜单
右侧详细页面

功能分析

  • widthMeasureSpec:期望值

    • 组成: 32位的010101010101011010101组成
    • 头2位:代表的是模式
      1. UNSPECIFIED: 不确定,随意
      2. EXACTLY:精确的
      3. AT_MOST:最大的
    • 后30位:数值
  • scrollTo:

    1. 移动的是手机的屏幕
    2. 标准移动
  • scrollBy:

    1. 移动的是手机的屏幕
    2. 增量移动
  • Scroller: 用来模拟数据变化

    1. computeScroll()

代码实现

  • 页面布局
    • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.cdw.slidingmenu.MainActivity">

    <com.cdw.slidingmenu.SlidingMenu
        android:id="@+id/sm"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <!--左侧菜单-->
        <include layout="@layout/left"/>
        <!--右侧内容-->
        <include layout="@layout/content"/>
    </com.cdw.slidingmenu.SlidingMenu>
</RelativeLayout>
  • 左菜单(left.xml)
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="200dp"
            android:layout_height="match_parent"
            android:background="@drawable/menu_bg"
    android:scrollbars="none">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_news"
            android:text="新闻"/>

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_read"
            android:text="订阅"/>

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_local"
            android:text="本地"/>

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_ties"
            android:text="跟帖"/>

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_pics"
            android:text="图片"/>

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_ugc"
            android:text="话题"/>

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_vote"
            android:text="投票"/>

        <TextView
            style="@style/tab_style"
            android:drawableLeft="@drawable/tab_focus"
            android:text="聚合读物"/>

    </LinearLayout>
</ScrollView>
  • 右边主界面(content.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="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/top_bar_bg">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="clickBack"
            android:src="@drawable/main_back"/>
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/top_bar_divider"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="今日头条"
            android:textSize="25sp"
            android:layout_margin="5dp"
            android:textColor="@android:color/white"
            android:layout_gravity="center_vertical"/>
    </LinearLayout>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="新闻内容"
        android:textSize="25sp"
        android:layout_margin="5dp"
        android:gravity="center"/>

</LinearLayout>
  • drawable目录下tab_bg.xml选择器
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="#3333ffff" android:state_pressed="true"/>
    <item android:drawable="@android:color/transparent"/>
</selector>
  • styles.xml
<style name="tab_style">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textColor">@android:color/white</item>
        <item name="android:textSize">24sp</item>
        <item name="android:paddingTop">10dp</item>
        <item name="android:paddingLeft">20dp</item>
        <item name="android:paddingBottom">10dp</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:drawablePadding">15dp</item>
        <item name="android:clickable">true</item>
        <item name="android:onClick">clickTab</item>
        <item name="android:background">@drawable/tab_bg</item>
    </style>
  • SlidingMenu.java
package com.cdw.slidingmenu;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;

/**
 * Created by dongwei on 2016/8/2.
 */
public class SlidingMenu extends ViewGroup {
    private View mLeftView;
    private View mContentView;
    private int mLeftWidth;
    private float mDownX;
    private float mDownY;
    private Scroller mScroller;
    private boolean isLeftShow = false;

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

    public SlidingMenu(Context context, AttributeSet attrs) {
        super(context, attrs);

        mScroller = new Scroller(context);
    }

    @Override
    protected void onFinishInflate() {
        //xml加载完成时
        mLeftView = getChildAt(0);
        mContentView = getChildAt(1);

        LayoutParams params = mLeftView.getLayoutParams();
        mLeftWidth = params.width;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //测量孩子
        int leftWidthMeasureSpec = MeasureSpec.makeMeasureSpec(mLeftWidth, MeasureSpec.EXACTLY);
        mLeftView.measure(leftWidthMeasureSpec, heightMeasureSpec);
        mContentView.measure(widthMeasureSpec, heightMeasureSpec);
        //设置自己的宽度和高度
        int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
        int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(measuredWidth, measuredHeight);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int width = mLeftView.getMeasuredWidth();
        int height = mLeftView.getMeasuredHeight();
        //给左侧布局

        int lvLeft = -width;
        int lvTop = 0;
        int lvRight = 0;
        int lvBottom = height;
        mLeftView.layout(lvLeft, lvTop, lvRight, lvBottom);

        //给右侧布局
        int cLeft = 0;
        int cTop = 0;
        int cRight = mContentView.getMeasuredWidth();
        int cBottom = mContentView.getMeasuredHeight();
        mContentView.layout(cLeft, cTop, cRight, cBottom);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                mDownX = ev.getX();
                mDownY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float moveX = ev.getX();
                float moveY = ev.getY();

                if (Math.abs(moveX - mDownX) > Math.abs(moveY - mDownY)){
                    //水平方向移动
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:

                break;
            default:
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                mDownX = event.getX();
                mDownY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float moveX = event.getX();
                float moveY = event.getY();

                int diffX = (int) (mDownX - moveX + 0.5f);

                int scrollX = getScrollX() + diffX;
                if (scrollX < 0 && scrollX < -mLeftView.getMeasuredWidth()){
                    scrollTo(-mLeftView.getMeasuredWidth(), 0);
                }else if (scrollX > 0){
                    scrollTo(0, 0);
                }else {
                    scrollBy(diffX, 0);
                }

                mDownX = moveX;
                mDownY = moveY;
                break;
            case MotionEvent.ACTION_UP:
                //判断是打开还是关闭
                int width = mLeftView.getMeasuredWidth();
                int currentX = getScrollX();
                float middle = -width / 2f;
                switchMenu(currentX <= middle);
                break;
            default:
                break;
        }
        return true;
    }

    private void switchMenu(boolean showLeft) {
        isLeftShow = showLeft;
        int width = mLeftView.getMeasuredWidth();
        int currentX = getScrollX();
        if (!showLeft){
            //scrollTo(0, 0);

            int startX = currentX;
            int startY = 0;
            int endX = 0;
            int endY = 0;
            int dx = endX - startX;
            int dy = endY - startY;
            int duration = Math.abs(dx) * 10;
            if (duration >= 600){
                duration = 600;
            }
            //模拟数据变化
            mScroller.startScroll(startX, startY, dx, dy, duration);
        }else {
            //scrollTo(-width, 0);

            int startX = currentX;
            int startY = 0;
            int endX = -width;
            int endY = 0;
            int dx = endX - startX;
            int dy = endY - startY;
            int duration = Math.abs(dx) * 10;
            if (duration >= 600){
                duration = 600;
            }
            mScroller.startScroll(startX, startY, dx, dy, duration);
        }

        invalidate();
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()){
            //更新位置
            scrollTo(mScroller.getCurrX(), 0);
            invalidate();
        }
    }

    public void toggle(){
        switchMenu(!isLeftShow);
    }
}
  • mainActivity.java
package com.cdw.slidingmenu;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

    private SlidingMenu menu;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        menu = (SlidingMenu) findViewById(R.id.sm);
    }

    public void clickTab(View view){
        String text = ((TextView)view).getText().toString();
        Toast.makeText(this, "点击了" + text, Toast.LENGTH_SHORT).show();
        menu.toggle();
    }

    public void clickBack(View view){
        menu.toggle();
    }
}

项目链接https://github.com/ChenDongWei/Android/tree/ec78b9b3d2d3bb22b51b0784d26dca18960ab01a/slidingmenu

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值