效果

主要步骤:

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. Java基础学习总结(12)——一哈希编码HashCode

    一.哈希编码 现在是站在JAVA虚拟机的角度来看内存里面的布局,站在JAVA虚拟机的角度,在内存里面有好多好多个对象,这里用椭圆来代表一个个对象.一个程序运行起来的时候,可能会有很多个对象在内存里面分 ...

  2. POJ——T 1986 Distance Queries

    http://poj.org/problem?id=1986 Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 14383   ...

  3. 炜煌E30 E31微型热敏打印机 STM32 串口驱动

    设置为汉字模式 十六进制 命令:1C    26 USART_SendData(USART2,0x1C); while(USART_GetFlagStatus(USART2,USART_FLAG_TC ...

  4. 一起talk C栗子吧(第八十一回:C语言实例--进程停止)

    各位看官们,大家好,上一回中咱们说的是进程相互排斥的样例,这一回咱们说的样例是:进程停止.闲话休提,言归正转. 让我们一起talk C栗子吧! 我们在前面的章回中介绍了怎样创建进程,只是没有介绍停止进 ...

  5. FSM之三--代码风格

    FSM设计之一http://www.cnblogs.com/qiweiwang/archive/2010/11/28/1890244.html Moore型状态机与mealy型状态机相比,由于其状态输 ...

  6. Android - TextureView, SurfaceView和GLSurfaceView 以及 SurfaceTexture

    这几个概念比较绕, 又比较相近. 初看比较糊涂, 把握关键点就好. 关键字 View SurfaceViewGLSurfaceViewTextureView这三个后缀都是View, 所以这三个东西都是 ...

  7. 9.java 操作mongodb插入、读取、修改以及删除基础

    1 package mongodb; import java.net.UnknownHostException; import java.util.ArrayList; import java.uti ...

  8. @Transactional 事务注解

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE, rollbackFor = ...

  9. VC++中的延时函数

    原文链接:http://www.educity.cn/develop/478947.html VC中提供了很多关于时间操作的函数,编写程序时我们可以跟据定时的不同精度要求选择不同的时间函数来完成定时和 ...

  10. 天意——thinkphp方法名大小写问题

    今天星期六,晚一小时上班.早起后背了会单词就骑自行车上班了.我是个有豪车梦的男生,每看到什么保时捷啊,雷克萨斯啊开过都会呆呆的看一会.现在虽然我买不上车,但是我可以靠我自己先买一台帅气的大摩托啊哈哈. ...