Android自定义组件——四个方向滑动的菜单实现
今天无意中实现了一个四个方向滑动的菜单,感觉挺好玩,滑动起来很顺手,既然已经做出来了就贴出来让大家也玩弄一下。
一、效果演示
(说明:目前没有安装Android模拟器,制作的动态图片太卡了,就贴一下静态图片吧,实际效果可以下载源代码查看)
(向上滑动)
(向下滑动)
(向左滑动)
(向右滑动)
二、实现过程介绍
1、放置5个View (分别是上下左右中)
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- mTopView.layout(0, -mViewHeight, mViewWidth, 0);
- mBottomView.layout(0, mViewHeight, mViewWidth, 2 * mViewHeight);
- mCenterView.layout(0, 0, mViewWidth, mViewHeight);
- mLeftView.layout(-mViewWidth, 0, 0, mViewHeight);
- mRightView.layout(mViewWidth, 0, 2 * mViewWidth, mViewHeight);
- }
转载请说明出处:http://blog.csdn.net/dawanganban
2、通过onTouchEvent事件来判断移动方向
- private float mDownY;
- private float mDownX;
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- int disY;
- int disX;
- float eventY = event.getY();
- float eventX = event.getX();
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mDownY = eventY;
- mDownX = eventX;
- break;
- case MotionEvent.ACTION_UP:
- disY = (int)(eventY - mDownY);
- disX = (int)(eventX - mDownX);
- if(Math.abs(disY) > Math.abs(disX)){
- if(Math.abs(disY) > MIN_VIEW_HEIGHT / 2){
- if(disY > 0){ //向下滑动
- Log.d(TAG, "TO_BOTTOM");
- changeToBottom();
- }else{ //向上滑动
- Log.d(TAG, "TO_TOP");
- changeToTop();
- }
- }
- }else{
- if(Math.abs(disX) > MIN_VIEW_WIDTH / 2){
- if(disX > 0){ //向右滑动
- Log.d(TAG, "TO_RIGHT");
- changeToRight();
- }else{ //向左滑动
- Log.d(TAG, "TO_LEFT");
- changeToLeft();
- }
- }
- }
- break;
- default:
- break;
- }
- return true;
- }
3、通过computerScroll()方法实现平滑移动
- @Override
- public void computeScroll() {
- super.computeScroll();
- if(mScroller.computeScrollOffset()){
- scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
- postInvalidate();
- }
- }
4、判断临界条件(否则会一直向一个方向滑动)
- int[] location = new int[2];
- mCenterView.getLocationOnScreen(location);
- if(location[1] >= mViewHeight - MIN_VIEW_HEIGHT * 2) return;
例如上面代码就是判断向下滑动的临界条件,location[1]代表中间View的y坐标(相对于屏幕)。
三、整个View的源码
- package com.example.testmx4update;
- import android.content.Context;
- import android.graphics.Color;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.Scroller;
- /**
- * 自定义可以拖动的View
- * @author 阳光小强 http://blog.csdn.net/dawanganban
- *
- */
- public class MyCanPullView extends ViewGroup{
- private static final int MIN_VIEW_HEIGHT = 200;
- private static final int MIN_VIEW_WIDTH = 400;
- private static final String TAG = "TEST";
- private int mViewHeight;
- private int mViewWidth;
- private View mTopView;
- private View mBottomView;
- private View mCenterView;
- private View mLeftView;
- private View mRightView;
- private Scroller mScroller;
- public MyCanPullView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initView(context);
- mScroller = new Scroller(context);
- }
- private void initView(Context context) {
- setTopView(context);
- setBottomView(context);
- setCenterView(context);
- setLeftView(context);
- setRightView(context);
- }
- private float mDownY;
- private float mDownX;
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- int disY;
- int disX;
- float eventY = event.getY();
- float eventX = event.getX();
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mDownY = eventY;
- mDownX = eventX;
- break;
- case MotionEvent.ACTION_UP:
- disY = (int)(eventY - mDownY);
- disX = (int)(eventX - mDownX);
- if(Math.abs(disY) > Math.abs(disX)){
- if(Math.abs(disY) > MIN_VIEW_HEIGHT / 2){
- if(disY > 0){ //向下滑动
- Log.d(TAG, "TO_BOTTOM");
- changeToBottom();
- }else{ //向上滑动
- Log.d(TAG, "TO_TOP");
- changeToTop();
- }
- }
- }else{
- if(Math.abs(disX) > MIN_VIEW_WIDTH / 2){
- if(disX > 0){ //向右滑动
- Log.d(TAG, "TO_RIGHT");
- changeToRight();
- }else{ //向左滑动
- Log.d(TAG, "TO_LEFT");
- changeToLeft();
- }
- }
- }
- break;
- default:
- break;
- }
- return true;
- }
- private void changeToBottom(){
- int[] location = new int[2];
- mCenterView.getLocationOnScreen(location);
- if(location[1] >= mViewHeight - MIN_VIEW_HEIGHT * 2) return;
- int dy = (int)(mViewHeight - MIN_VIEW_HEIGHT);
- mScroller.startScroll(0, getScrollY(), 0, -dy, 500);
- invalidate();
- }
- private void changeToTop(){
- int[] location = new int[2];
- mTopView.getLocationOnScreen(location);
- if(location[1] <= -mViewHeight - MIN_VIEW_HEIGHT / 2) return;
- int dy = (int)(mViewHeight - MIN_VIEW_HEIGHT);
- mScroller.startScroll(0, getScrollY(), 0, dy, 500);
- invalidate();
- }
- private void changeToRight(){
- int[] location = new int[2];
- mCenterView.getLocationOnScreen(location);
- if(location[0] >= mViewWidth - MIN_VIEW_WIDTH * 2) return;
- int dx = (int)(mViewWidth - MIN_VIEW_WIDTH);
- mScroller.startScroll(getScrollX(), 0, -dx, 0, 500);
- invalidate();
- }
- private void changeToLeft(){
- Log.d(TAG, "TO_LEFT");
- int[] location = new int[2];
- mLeftView.getLocationOnScreen(location);
- if(location[0] <= -mViewWidth - MIN_VIEW_WIDTH / 2) return;
- int dx = (int)(mViewWidth - MIN_VIEW_WIDTH);
- mScroller.startScroll(getScrollX(), 0, dx, 0, 500);
- invalidate();
- }
- @Override
- public void computeScroll() {
- super.computeScroll();
- if(mScroller.computeScrollOffset()){
- scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
- postInvalidate();
- }
- }
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- mTopView.layout(0, -mViewHeight, mViewWidth, 0);
- mBottomView.layout(0, mViewHeight, mViewWidth, 2 * mViewHeight);
- mCenterView.layout(0, 0, mViewWidth, mViewHeight);
- mLeftView.layout(-mViewWidth, 0, 0, mViewHeight);
- mRightView.layout(mViewWidth, 0, 2 * mViewWidth, mViewHeight);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- //获取整个View的宽高
- mViewWidth = MeasureSpec.getSize(widthMeasureSpec);
- mViewHeight = MeasureSpec.getSize(heightMeasureSpec);
- }
- private void setTopView(Context context){
- View topButton = new View(context);
- topButton.setBackgroundColor(Color.RED);
- mTopView = topButton;
- this.addView(mTopView);
- }
- private void setBottomView(Context context){
- View bottomButton = new View(context);
- bottomButton.setBackgroundColor(Color.GREEN);
- mBottomView = bottomButton;
- this.addView(mBottomView);
- }
- private void setCenterView(Context context){
- View centerButton = new View(context);
- centerButton.setBackgroundColor(Color.WHITE);
- mCenterView = centerButton;
- this.addView(mCenterView);
- }
- private void setLeftView(Context context){
- View leftButton = new View(context);
- leftButton.setBackgroundColor(Color.BLUE);
- mLeftView = leftButton;
- this.addView(mLeftView);
- }
- private void setRightView(Context context){
- View rightButton = new View(context);
- rightButton.setBackgroundColor(Color.YELLOW);
- mRightView = rightButton;
- this.addView(mRightView);
- }
- }
获取全部源代码,请加群在群共享中获取(142979499)
Android自定义组件——四个方向滑动的菜单实现的更多相关文章
- Android自定义组件系列【15】——四个方向滑动的菜单实现
今天无意中实现了一个四个方向滑动的菜单,感觉挺好玩,滑动起来很顺手,既然已经做出来了就贴出来让大家也玩弄一下. 一.效果演示 (说明:目前没有安装Android模拟器,制作的动态图片太卡了,就贴一下静 ...
- Android自定义组件系列【4】——自定义ViewGroup实现双侧滑动
在上一篇文章<Android自定义组件系列[3]--自定义ViewGroup实现侧滑>中实现了仿Facebook和人人网的侧滑效果,这一篇我们将接着上一篇来实现双面滑动的效果. 1.布局示 ...
- Android自定义组件系列【7】——进阶实践(4)
上一篇<Android自定义组件系列[6]--进阶实践(3)>中补充了关于Android中事件分发的过程知识,这一篇我们接着来分析任老师的<可下拉的PinnedHeaderExpan ...
- Android自定义视图四:定制onMeasure强制显示为方形
这个系列是老外写的,干货!翻译出来一起学习.如有不妥,不吝赐教! Android自定义视图一:扩展现有的视图,添加新的XML属性 Android自定义视图二:如何绘制内容 Android自定义视图三: ...
- Android自定义组件之自动换行及宽度自适应View:WordWrapView
目的: 自定义一个ViewGroup,里面的子view都是TextView,每个子view TextView的宽度随内容自适应且每行的子View的个数自适应,并可以自动换行 一:效果图 二:代码 整 ...
- Android自定义组件系列【5】——进阶实践(2)
上一篇<Android自定义组件系列[5]--进阶实践(1)>中对任老师的<可下拉的PinnedHeaderExpandableListView的实现>前一部分进行了实现,这一 ...
- Android自定义组件系列【6】——进阶实践(3)
上一篇<Android自定义组件系列[5]--进阶实践(2)>继续对任老师的<可下拉的PinnedHeaderExpandableListView的实现>进行了分析,这一篇计划 ...
- Android自定义组件系列【3】——自定义ViewGroup实现侧滑
有关自定义ViewGroup的文章已经很多了,我为什么写这篇文章,对于初学者或者对自定义组件比较生疏的朋友虽然可以拿来主义的用了,但是要一步一步的实现和了解其中的过程和原理才能真真脱离别人的代码,举一 ...
- Android 自定义组件之如何实现自定义组件
参考链接:http://blog.csdn.net/jjwwmlp456/article/details/41076699 简介 Android提供了用于构建UI的强大的组件模型.两个基类:View和 ...
随机推荐
- c# 正则实践
Regex reg = new Regex(@"<img[\s]+src[\s]*=[\s]*['""](?<picPath>.*)['"&q ...
- 有术:DIY代理服务器
FQ有术:DIY代理服务器 公司HTTP代理穿透+手機ShadowSocks+SSH翻牆 利用SSH代理爬墙 http://bestvpnchina.net/
- mysql4.5 更改密码,登录命令行闪退
登录到命令行 修改密码: 格式:mysql> set password for 用户名@localhost = password('新密码'); 例子:mysql> set passwor ...
- touch事件的分发和消费机制
Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev).onInterceptTouchEvent(MotionEvent ev). ...
- C++ 中的constkeyword
为什么使用const?採用符号常量写出的代码更easy维护:指针经常是边读边移动,而不是边写边移动:很多函数參数是仅仅读不写的.const最常见用途是作为数组的界和switch分情况标号(也能够用枚举 ...
- WPF TextBox属性IsReadOnlyCaretVisible
纠结了半天WPF下只读的TextBox怎么显示输入焦点提示,发现wpf 4中已有新属性“IsReadOnlyCaretVisible”,大善^_^
- 百度编辑器插入视频、iframe 失败
插入失败是因为编辑器的xssFilter过滤,导致插入出现异常 文件位置:ueditor.config.js ,大概在428行加上 video: ['autoplay', 'controls', 'l ...
- Objective-C语法之字符串NSString去掉前后空格或回车符(可以是NSCharacterSet类型的其它字符)
main.m #import <Foundation/Foundation.h> #import "NSString+Trim.h" int main(int argc ...
- mysql查询某个库的表个数
SELECT COUNT(1) FROM information_schema.tables WHERE table_schema = 'leleli'; --解释:数据库名叫“leleli”
- MongoDB的php可视化管理工具
使用MongoDB命令查看很不方便 于是想把爬来的数据导出来,看爬来的数据是否正确 打开cmd,执行 mongoexport -d test -c blogs --csv -f title,link, ...