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和 ...
随机推荐
- (原创)OpenStack服务如何使用Keystone(一)---Keystone端的操作
(一)Keystone端的操作 (二)如何在OpenStack服务上部署Keystone中间件 (三)详细配置keystonemiddleware OpenStack项目如果要使用Keystone作为 ...
- Kubeadm 安装
version 1.7.0 已解决: echo "1" > /proc/sys/net/bridge/bridge-nf-call-iptables error: faile ...
- Intellij MyBatisPlus Plugin插件破解
1. 下载原始的MyBatisPlus Plugin插件. 2. 下载替换包,请根据实际版本下载: https://github.com/myoss/profile/tree/master/idea/ ...
- 绝对震撼 10个实用的jQuery/HTML5插件
在HTML5的世界里,我们见证了无数的特效奇迹,但很多特效我们很难在网页中应用,今天我们要分享10款效果震撼但是又比较实用的jQuery/HTML5插件,希望这些项目在应用的过程中也能给你带来设计灵感 ...
- Oracle中已知字段名查询所在的表名
select table_name from user_tab_columns where column_name = '字段名'; 这是网上查到的,地址如下:http://blog.163.com/ ...
- EventBus的思路和一些反思
本文版权归博客园和作者吴双本人共同所有 转载和爬虫请注明原文地址 www.cnblogs.com/tdws C#本地实现的和Redis Set实现的,实际上都是要维护一个Events和Handle ...
- android中YUV转RGB的方法
在一个外国网站上看到一段YUV转RGB的程序很不错,根据维基上的知识,方法应该是没问题的,自己也用过了,效果没问题. 首先说一下android上preview中每一帧的信息都是YUV420的,或者叫N ...
- Thinkphp5笔记五:配置data文件夹
如果你看项目下的各种文件,有种乱七八糟的感觉的话,你就可以进行以下配置. 配置data文件夹的,整理各种文件,让看起来舒服些. 一.设置runtime文件夹 index.php define('RUN ...
- Java学习之——Java Serializable
1.什么是Serializable接口? http://en.wikipedia.org/wiki/Serialization Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个 ...
- Vue.nextTick和Vue.$nextTick
`Vue.nextTick(callback)`,当数据发生变化,更新后执行回调. `Vue.$nextTick(callback)`,当dom发生变化,更新后执行的回调. 参考原文:http://w ...