效果

主要步骤:

1. 在xml布局里摆放内容. include
    2. 在自定义ViewGroup里, 进行measure测量, layout布局
    3. 响应用户的触摸事件
    4. int scrollX = (int) (downX - moveX);
    5. getScrollX()获取当前滚动到的位置
    6. 平滑动画

先看布局

layout_left

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="240dp"
android:layout_height="match_parent"> <LinearLayout
android:layout_width="240dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@drawable/menu_bg">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:background="@drawable/selector_bg"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:text="新闻"
android:clickable="true"
android:textColor="#ADCFD6"
android:drawableLeft="@drawable/tab_news"
android:textSize="18sp"/> </LinearLayout>
</ScrollView>

layout_content

<?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:background="#FFFFFF"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/top_bar_bg">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/main_back"
android:background="@null"/>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="@drawable/top_bar_divider"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="每日新闻"
android:textSize="25sp"
android:layout_gravity="center"/> </LinearLayout> </LinearLayout>

activity_main

<?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.example.xw.mystudeydemo.MainActivity"> <com.example.mystudydemo.SlideMeun
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/layout_left"/>
<include layout="@layout/layoit_content"/>
</com.example.mystudydemo.SlideMeun>
</RelativeLayout>

布局中需要注意的是,layout_content中我们把整体布局背景设置成了android:background="#FFFFFF",这是因为我们需要他完全遮住下面的那层layout_left.xml

layout_left的状态选择器

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@color/bg_pressed"/>
<item android:drawable="@android:color/transparent"/>
</selector>

二,写自定义控件

package com.example.mystudydemo;
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 xw on 2016/8/6.
*/
public class SlideMeun extends ViewGroup{
private float downX;
private float moveX;
private Scroller scroller;
/**
* 侧滑面板控件, 抽屉面板.
* @author poplar
*
* 测量 摆放 绘制
measure -> layout -> draw
| | |
onMeasure -> onLayout -> onDraw 重写这些方法, 实现自定义控件 View流程
onMeasure() (在这个方法里指定自己的宽高) -> onDraw() (绘制自己的内容) ViewGroup流程
onMeasure() (指定自己的宽高, 所有子View的宽高)-> onLayout() (摆放所有子View) -> onDraw() (绘制内容)
*
*/ public SlideMeun(Context context) {
super(context);
init(context);
} public SlideMeun(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
} public SlideMeun(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
// 初始化滚动器
scroller=new Scroller(context);
} /**
* 测量并设置 所有子View的宽高
* widthMeasureSpec: 当前控件的宽度测量规则
* heightMeasureSpec: 当前控件的高度测量规则
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 指定左面板的宽高
View leftMenu=getChildAt(0);
leftMenu.measure(leftMenu.getLayoutParams().width,heightMeasureSpec);
// 指定主面板的宽高
View mainMenu=getChildAt(1);
mainMenu.measure(mainMenu.getLayoutParams().width,heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} @Override protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 摆放内容, 左面板,隐藏
View leftMenu=getChildAt(0);
leftMenu.layout(-leftMenu.getMeasuredWidth(),0,0,b); // 主面板
View mainMenu=getChildAt(1);
mainMenu.layout(l,t,r,b); } @Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
downX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
moveX =event.getX(); // 将要发生的偏移量/变化量
int scrollX=(int)(downX-moveX);
// 计算将要滚动到的位置, 判断是否会超出去, 超出去了.不执行scrollBy
// getScrollX() 当前滚动到的位置
int newposition=getScrollX()+scrollX;
if(newposition<-getChildAt(0).getMeasuredWidth()){ // 限定左边界
scrollTo(-getChildAt(0).getMeasuredWidth(), 0);
}
else if(newposition>0){ // 限定右边界
scrollTo(0, 0);
}
else{
// 让变化量生效
scrollBy(scrollX,0);
}
downX=moveX;
break;
case MotionEvent.ACTION_UP: int leftcenter=-(int)(getChildAt(0).getMeasuredWidth()/2.0f);
int startX=getScrollX();
int dx=0;
// 根据当前滚动到的位置, 和左面板的一半进行比较
if(startX<leftcenter){
// 打开, 切换成菜单面板
dx=-getChildAt(0).getMeasuredWidth()-startX; }
else{
// 关闭, 切换成主面板
dx=0-startX; }
int duration=Math.abs(dx*10);
scroller.startScroll(startX, 0, dx, 0, duration);
invalidate(); //重绘界面 -> drawChild() -> computeScroll();
break; default:
break;
} return true;//消费事件
} @Override ////2. 维持动画的继续
public void computeScroll() { super.computeScroll();
if(scroller.computeScrollOffset()){
int currX=scroller.getCurrX();
scrollTo(currX, 0);
invalidate();
}
}
}

三, MainActivity

package com.example.mystudydemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main); } }

自定义控件学习——仿qq侧滑栏的更多相关文章

  1. android开发学习 ------- 仿QQ侧滑效果的实现

    需要做一个仿QQ侧滑删除的一个效果: 一开始是毫无头绪,百度找思路,找到  https://blog.csdn.net/xiaxiazaizai01/article/details/53036994  ...

  2. iOS仿QQ侧滑菜单、登录按钮动画、仿斗鱼直播APP、城市选择器、自动布局等源码

    iOS精选源码 QQ侧滑菜单,右滑菜单,QQ展开菜单,QQ好友分组 登录按钮 3分钟快捷创建高性能轮播图 ScrollView嵌套ScrolloView(UITableView .UICollecti ...

  3. Android学习总结——DrawerLayout 侧滑栏点击事件穿透

    使用DrawerLayout实现侧滑栏功能时,点击侧滑栏空白处时,主界面会获得事件. 解决方法:侧滑栏布局添加 android:clickable="true"

  4. 仿QQ侧滑菜单<大自然的搬运工-代码不是我的>

    1.记录下效果图 2.二个工具类 package myapplication.com.myapplicationfortest.utils; import android.util.Log; /** ...

  5. OC仿QQ侧滑

    之前做侧滑用的控件的DDMenu,总感觉好像差了点什么,自己尝试写了一个,三层叠加,感觉效果不理想,偶然间看到了一篇博客,与大家分享,再次申明,该代码不是我写的,只是为了给自己留一个查找资料的机会 下 ...

  6. 小程序仿QQ侧滑例子

    缩放:wxml <!--page/one/index.wxml--> <view class="page"> <view class="pa ...

  7. 如鹏网仿QQ侧滑菜单:ResideMenu组件的使用笔记整理+Demo

    ResideMenu菜单 课堂笔记: https://github.com/SpecialCyCi/AndroidResideMenu Github:如何使用开源组件1. 下载 下载方式: 1. 项目 ...

  8. 手势仿QQ侧滑---秀清

    // // SlideViewController.h // qqcehua // // Created by 张秀清 on 15/5/25. // Copyright (c) 2015年 张秀清. ...

  9. 史上最简单,一步集成侧滑(删除)菜单,高仿QQ、IOS。

    重要的话 开头说,not for the RecyclerView or ListView, for the Any ViewGroup. 本控件不依赖任何父布局,不是针对 RecyclerView. ...

随机推荐

  1. gluPerspective和gluLookAt的关系

    参考文章 GL学习笔记(2) - 终于搞明白gluPerspective和gluLookAt的关系了(zz) gluPerspective的具体含义 解密--神秘的gluPerspective 函数原 ...

  2. 新一代企业即时通信系统 -- 傲瑞通(OrayTalk)

    傲瑞通(OrayTalk)是我们为企业专门打造的新一代企业即时通讯平台,功能强大丰富.像组织结构.文字/语音/视频会话.文件传送.远程协助.消息记录等功能都有,而且留有接口可与企业遗留系统进行集成. ...

  3. ReactNative之Flux框架的使用

    概述 流程图 项目结构 View Components actions Dispatcher Stores 感谢 概述 React Native 能够说非常火,非常多bat的项目都在使用.不用发版就能 ...

  4. codeforces 710E Generate a String(简单dp)

    传送门:http://codeforces.com/problemset/problem/710/E 分析: 让你写一个全由"a"组成的长为n的串,告诉你两种操作,第一种:插入一个 ...

  5. codeforces 710A King Moves(水)

    output standard output The only king stands on the standard chess board. You are given his position ...

  6. Laravel 框架指定路由关闭 csrf

    修改 app\Http\Middleware\VerifyCsrfToken.php 内容: <?php namespace App\Http\Middleware; use Closure; ...

  7. 学习推荐《精通Python网络爬虫:核心技术、框架与项目实战》中文PDF+源代码

    随着大数据时代的到来,我们经常需要在海量数据的互联网环境中搜集一些特定的数据并对其进行分析,我们可以使用网络爬虫对这些特定的数据进行爬取,并对一些无关的数据进行过滤,将目标数据筛选出来.对特定的数据进 ...

  8. Spring 热点面试题:

    1.谈谈你对Springaop的理解? spring用代理类包裹切面,把他们织入到Spring管理的bean中.也就是说代理类伪装成目标类,它会截取对目标类中方法的调用,让调用者对目标类的调用都先变成 ...

  9. Linux发行版centos, ubuntu等

    公司装的是centos,centos其实就是无支持版的redhat. redhat是一个服务器的操作系统它的稳定性是比较高的,同时提供在线管理服务,服务器故障预警等,当然前提是要购买昂贵的服务. Su ...

  10. microsoft SQL server,错误2

    大二下開始学习数据库,一開始就把数据库装了,结果数据库第一节实验课就是教我们装数据库,而且要在自己机子上装,还要实验报告和截图.老师叫我把原本的卸载掉, 于是对着网上一系列的操作卸载server删除目 ...