1116text(推拉门)

本文介绍了一种基于Android的3D滑动布局实现方法,通过自定义View和使用Camera API来实现视图的3D效果,同时通过监听触摸事件完成侧滑菜单的展开与收起。

先说发现的一个小问题:OnCreate()有两个,一个是public一个是protected,貌似以前也遇过这种问题,再深究
第二
赏析代码
这个推拉门主要是先创建左边布局的镜像文件,就是那个什么3D,把他垫在父布局左边,检测到滑动的时候给左边要显示的布局拍个照,然后对这个拍照图片把玩,目前我的理解是这个



import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.View;
import android.graphics.Camera;
/**
 * Created by Administrator on 2015/11/14.
 */
public class Image3dView extends View {


    /**
     * 源视图,用于生成图片对象。
     */
    private View sourceView;

    /**
     * 根据传入的源视图生成的图片对象。
     */
    private Bitmap sourceBitmap;

    /**
     * 源视图的宽度。
     */
    private float sourceWidth;

    /**
     * Matrix对象,用于对图片进行矩阵操作。
     */
    private Matrix matrix = new Matrix();

    /**
     * Camera对象,用于对图片进行三维操作。
     */
    private Camera camera = new Camera();

    /**
     * Image3dView的构造函数
     *
     * @param context
     * @param attrs
     */
    public Image3dView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * 提供外部接口,允许向Image3dView传入源视图。
     *
     * @param view
     *            传入的源视图
     */
    public void setSourceView(View view) {
        sourceView = view;
        sourceWidth = sourceView.getWidth();
    }

    /**
     * 清除掉缓存的图片对象。
     */
    public void clearSourceBitmap() {
        if (sourceBitmap != null) {
            sourceBitmap = null;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (sourceBitmap == null) {
            getSourceBitmap();
        }
        // 计算图片需要旋转的角度
        float degree = 90 - (90 / sourceWidth) * getWidth();
        camera.save();
        camera.rotateY(degree);
        camera.getMatrix(matrix);
        camera.restore();
        // 将旋转的中心点移动到屏幕左边缘的中间位置
        matrix.preTranslate(0,-getHeight() / 2);
        matrix.postTranslate(0,getHeight() / 2);
        canvas.drawBitmap(sourceBitmap, matrix, null);
    }

    /**
     * 获取源视图对应的图片对象。
     */
    private void getSourceBitmap() {
        if (sourceView != null) {
            sourceView.setDrawingCacheEnabled(true);
            sourceView.layout(0, 0, sourceView.getWidth(), sourceView.getHeight());
            sourceView.buildDrawingCache();
            sourceBitmap = sourceView.getDrawingCache();
        }
    }

}

上面这个代码可以赏析一下:
camera的主要作用是产生一个Matrix,view根据这个来设置宽度长度等等
canvas.drawBitmap(sourceBitmap, matrix, null);
也就是画一个虚拟图

这就是我说的那个垫屁股的

package com.com.fish.transcation.add;

import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.RelativeLayout;

import com.example.qqlike.R;

/**
 * Created by Administrator on 2015/11/14.
 */
public class ThreeDSlidingLayout extends RelativeLayout implements View.OnTouchListener {

    /**
     * 滚动显示和隐藏左侧布局时,手指滑动需要达到的速度。
     */
    public static final int SNAP_VELOCITY = 200;

    /**
     * 滑动状态的一种,表示未进行任何滑动。
     */
    public static final int DO_NOTHING = 0;

    /**
     * 滑动状态的一种,表示正在滑出左侧菜单。
     */
    public static final int SHOW_MENU = 1;

    /**
     * 滑动状态的一种,表示正在隐藏左侧菜单。
     */
    public static final int HIDE_MENU = 2;

    /**
     * 记录当前的滑动状态
     */
    private int slideState;

    /**
     * 屏幕宽度值。
     */
    private int screenWidth;

    /**
     * 右侧布局最多可以滑动到的左边缘。
     */
    private int leftEdge = 0;

    /**
     * 右侧布局最多可以滑动到的右边缘。
     */
    private int rightEdge = 0;

    /**
     * 在被判定为滚动之前用户手指可以移动的最大值。
     */
    private int touchSlop;

    /**
     * 记录手指按下时的横坐标。
     */
    private float xDown;

    /**
     * 记录手指按下时的纵坐标。
     */
    private float yDown;

    /**
     * 记录手指移动时的横坐标。
     */
    private float xMove;

    /**
     * 记录手指移动时的纵坐标。
     */
    private float yMove;

    /**
     * 记录手机抬起时的横坐标。
     */
    private float xUp;

    /**
     * 左侧布局当前是显示还是隐藏。只有完全显示或隐藏时才会更改此值,滑动过程中此值无效。
     */
    private boolean isLeftLayoutVisible;

    /**
     * 是否正在滑动。
     */
    private boolean isSliding;

    /**
     * 是否已加载过一次layout,这里onLayout中的初始化只需加载一次
     */
    private boolean loadOnce;

    /**
     * 左侧布局对象。
     */
    private View leftLayout;

    /**
     * 右侧布局对象。
     */
    private View rightLayout;

    /**
     * 在滑动过程中展示的3D视图
     */
    private Image3dView image3dView;

    /**
     * 用于监听侧滑事件的View。
     */
    private View mBindView;

    /**
     * 左侧布局的参数,通过此参数来重新确定左侧布局的宽度,以及更改leftMargin的值。
     */
    private MarginLayoutParams leftLayoutParams;

    /**
     * 右侧布局的参数,通过此参数来重新确定右侧布局的宽度。
     */
    private MarginLayoutParams rightLayoutParams;

    /**
     * 3D视图的参数,通过此参数来重新确定3D视图的宽度。
     */
    private ViewGroup.LayoutParams image3dViewParams;

    /**
     * 用于计算手指滑动的速度。速率追踪者
     */
    private VelocityTracker mVelocityTracker;

    /**
     * 重写SlidingLayout的构造函数,其中获取了屏幕的宽度。
     *
     * @param context
     * @param attrs
     */
    public ThreeDSlidingLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        screenWidth = wm.getDefaultDisplay().getWidth();
        touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

    /**
     * 绑定监听侧滑事件的View,即在绑定的View进行滑动才可以显示和隐藏左侧布局。
     *
     * @param bindView
     *            需要绑定的View对象。
     */
    public void setScrollEvent(View bindView) {
        mBindView = bindView;
        mBindView.setOnTouchListener(this);
    }

    /**
     * 将屏幕滚动到左侧布局界面,滚动速度设定为10.
     */
    public void scrollToLeftLayout() {
        image3dView.clearSourceBitmap();
        new ScrollTask().execute(-10);
    }

    /**
     * 将屏幕滚动到右侧布局界面,滚动速度设定为-10.
     */
    public void scrollToRightLayout() {
        image3dView.clearSourceBitmap();
        new ScrollTask().execute(10);
    }

    /**
     * 左侧布局是否完全显示出来,或完全隐藏,滑动过程中此值无效。
     *
     * @return 左侧布局完全显示返回true,完全隐藏返回false。
     */
    public boolean isLeftLayoutVisible() {
        return isLeftLayoutVisible;
    }

    /**
     * 在onLayout中重新设定左侧布局和右侧布局的参数。
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (changed && !loadOnce) {
            // 获取左侧布局对象
            leftLayout = findViewById(R.id.menu);
            leftLayoutParams = (MarginLayoutParams) leftLayout.getLayoutParams();
            rightEdge = -leftLayoutParams.width;
            // 获取右侧布局对象
            rightLayout = findViewById(R.id.content);
            rightLayoutParams = (MarginLayoutParams) rightLayout.getLayoutParams();
            rightLayoutParams.width = screenWidth;
            rightLayout.setLayoutParams(rightLayoutParams);

            // 获取3D视图对象
            image3dView = (Image3dView) findViewById(R.id.image_3d_view);//这个东西在布局中没有指定位置,只是在父左
            // 将左侧布局传入3D视图中作为生成源
            image3dView.setSourceView(leftLayout);
            loadOnce = true;
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        createVelocityTracker(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 手指按下时,记录按下时的横坐标
                xDown = event.getRawX();
                yDown = event.getRawY();
                slideState = DO_NOTHING;
                break;
            case MotionEvent.ACTION_MOVE:
                // 手指移动时,对比按下时的横坐标,计算出移动的距离,来调整右侧布局的leftMargin值,从而显示和隐藏左侧布局
                xMove = event.getRawX();
                yMove = event.getRawY();
                int moveDistanceX = (int) (xMove - xDown);
                int moveDistanceY = (int) (yMove - yDown);
                checkSlideState(moveDistanceX, moveDistanceY);
                switch (slideState) {
                    case SHOW_MENU:
                        rightLayoutParams.rightMargin = -moveDistanceX;
                        onSlide();
                        break;
                    case HIDE_MENU:
                        rightLayoutParams.rightMargin = rightEdge - moveDistanceX;
                        onSlide();
                        break;
                    default:
                        break;
                }
                break;
            case MotionEvent.ACTION_UP:
                xUp = event.getRawX();
                int upDistanceX = (int) (xUp - xDown);
                if (isSliding) {
                    // 手指抬起时,进行判断当前手势的意图
                    switch (slideState) {
                        case SHOW_MENU:
                            if (shouldScrollToLeftLayout()) {
                                scrollToLeftLayout();
                            } else {
                                scrollToRightLayout();
                            }
                            break;
                        case HIDE_MENU:
                            if (shouldScrollToRightLayout()) {
                                scrollToRightLayout();
                            } else {
                                scrollToLeftLayout();
                            }
                            break;
                        default:
                            break;
                    }
                } else if (upDistanceX < touchSlop && isLeftLayoutVisible) {
                    scrollToRightLayout();
                }
                recycleVelocityTracker();
                break;
        }
        if (v.isEnabled()) {
            if (isSliding) {
                unFocusBindView();
                return true;
            }
            if (isLeftLayoutVisible) {
                return true;
            }
            return false;
        }
        return true;
    }

    /**
     * 执行滑动过程中的逻辑操作,如边界检查,改变偏移值,可见性检查等。
     */
    private void onSlide() {
        checkSlideBorder();
        rightLayout.setLayoutParams(rightLayoutParams);
        image3dView.clearSourceBitmap();
        image3dViewParams = image3dView.getLayoutParams();
        image3dViewParams.width = -rightLayoutParams.rightMargin;
        // 滑动的同时改变3D视图的大小
        image3dView.setLayoutParams(image3dViewParams);
        // 保证在滑动过程中3D视图可见,左侧布局不可见
        showImage3dView();
    }

    /**
     * 根据手指移动的距离,判断当前用户的滑动意图,然后给slideState赋值成相应的滑动状态值。
     *
     * @param moveDistanceX
     *            横向移动的距离
     * @param moveDistanceY
     *            纵向移动的距离
     */
    private void checkSlideState(int moveDistanceX, int moveDistanceY) {
        if (isLeftLayoutVisible) {
            if (!isSliding && Math.abs(moveDistanceX) >= touchSlop && moveDistanceX < 0) {
                isSliding = true;
                slideState = HIDE_MENU;
            }
        } else if (!isSliding && Math.abs(moveDistanceX) >= touchSlop && moveDistanceX > 0
                && Math.abs(moveDistanceY) < touchSlop) {
            isSliding = true;
            slideState = SHOW_MENU;
        }
    }

    /**
     * 在滑动过程中检查左侧菜单的边界值,防止绑定布局滑出屏幕。
     * 这个如果不用会非常炫酷
     */
    private void checkSlideBorder() {
        if (rightLayoutParams.rightMargin > leftEdge) {
            rightLayoutParams.rightMargin = leftEdge;
        } else if (rightLayoutParams.rightMargin < rightEdge) {
            rightLayoutParams.rightMargin = rightEdge;
        }
    }

    /**
     * 判断是否应该滚动将左侧布局展示出来。如果手指移动距离大于屏幕的1/2,或者手指移动速度大于SNAP_VELOCITY,
     * 就认为应该滚动将左侧布局展示出来。
     *
     * @return 如果应该滚动将左侧布局展示出来返回true,否则返回false。
     */
    private boolean shouldScrollToLeftLayout() {
        return xUp - xDown > leftLayoutParams.width / 2 || getScrollVelocity() > SNAP_VELOCITY;
    }

    /**
     * 判断是否应该滚动将右侧布局展示出来。如果手指移动距离加上leftLayoutPadding大于屏幕的1/2,
     * 或者手指移动速度大于SNAP_VELOCITY, 就认为应该滚动将右侧布局展示出来。
     *
     * @return 如果应该滚动将右侧布局展示出来返回true,否则返回false。
     */
    private boolean shouldScrollToRightLayout() {
        return xDown - xUp > leftLayoutParams.width / 2 || getScrollVelocity() > SNAP_VELOCITY;
    }

    /**
     * 创建VelocityTracker对象,并将触摸事件加入到VelocityTracker当中。
     *
     * @param event
     *            右侧布局监听控件的滑动事件
     */
    private void createVelocityTracker(MotionEvent event) {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);
    }

    /**
     * 获取手指在右侧布局的监听View上的滑动速度。
     *
     * @return 滑动速度,以每秒钟移动了多少像素值为单位。
     */
    private int getScrollVelocity() {
        mVelocityTracker.computeCurrentVelocity(1000);
        int velocity = (int) mVelocityTracker.getXVelocity();
        return Math.abs(velocity);
    }

    /**
     * 回收VelocityTracker对象。
     */
    private void recycleVelocityTracker() {
        mVelocityTracker.recycle();
        mVelocityTracker = null;
    }

    /**
     * 使用可以获得焦点的控件在滑动的时候失去焦点。
     */
    private void unFocusBindView() {
        if (mBindView != null) {
            mBindView.setPressed(false);
            mBindView.setFocusable(false);
            mBindView.setFocusableInTouchMode(false);
        }
    }

    /**
     * 保证此时让左侧布局不可见,3D视图可见,从而让滑动过程中产生3D的效果。
     */
    private void showImage3dView() {
        if (image3dView.getVisibility() != View.VISIBLE) {
            image3dView.setVisibility(View.VISIBLE);
        }
        if (leftLayout.getVisibility() != View.INVISIBLE) {
            leftLayout.setVisibility(View.INVISIBLE);
        }
    }

    class ScrollTask extends AsyncTask<Integer, Integer, Integer> {

        @Override
        protected Integer doInBackground(Integer... speed) {
            int rightMargin = rightLayoutParams.rightMargin;
            // 根据传入的速度来滚动界面,当滚动到达左边界或右边界时,跳出循环。
            while (true) {
                rightMargin = rightMargin + speed[0];
                if (rightMargin < rightEdge) {
                    rightMargin = rightEdge;
                    break;
                }
                if (rightMargin > leftEdge) {
                    rightMargin = leftEdge;
                    break;
                }
                publishProgress(rightMargin);
                // 为了要有滚动效果产生,每次循环使线程睡眠5毫秒,这样肉眼才能够看到滚动动画。
                sleep(5);
            }
            if (speed[0] > 0) {
                isLeftLayoutVisible = false;
            } else {
                isLeftLayoutVisible = true;
            }
            isSliding = false;
            return rightMargin;
        }

        @Override
        protected void onProgressUpdate(Integer... rightMargin) {
            rightLayoutParams.rightMargin = rightMargin[0];
            rightLayout.setLayoutParams(rightLayoutParams);
            image3dViewParams = image3dView.getLayoutParams();
            image3dViewParams.width = -rightLayoutParams.rightMargin;
            image3dView.setLayoutParams(image3dViewParams);
            showImage3dView();
            unFocusBindView();
        }

        @Override
        protected void onPostExecute(Integer rightMargin) {
            rightLayoutParams.rightMargin = rightMargin;
            rightLayout.setLayoutParams(rightLayoutParams);
            image3dViewParams = image3dView.getLayoutParams();
            image3dViewParams.width = -rightLayoutParams.rightMargin;
            image3dView.setLayoutParams(image3dViewParams);
            if (isLeftLayoutVisible) {
                // 保证在滑动结束后左侧布局可见,3D视图不可见。
                image3dView.setVisibility(View.INVISIBLE);
                leftLayout.setVisibility(View.VISIBLE);
            }
        }
    }

    /**
     * 使当前线程睡眠指定的毫秒数。
     *
     * @param millis
     *            指定当前线程睡眠多久,以毫秒为单位
     */
    private void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

这个还没看全,代更新
checkSlideBorder这个如果不用的话…
这里写图片描述
这里写图片描述
这里写图片描述

这里主要是对布局进行触摸监控
然后进行移动等操作

内容概要:本文详细介绍了一个基于C++的养老院管理系统的设计与实现,旨在应对人口老龄化带来的管理挑战。系统通过整合住户档案、健康监测、护理计划、任务调度等核心功能,构建了从数据采集、清洗、AI风险预测到服务调度与可视化的完整技术架构。采用C++高性能服务端结合消息队列、规则引擎和机器学习模型,实现了健康状态实时监控、智能任务分配、异常告警推送等功能,并解决了多源数据整合、权限安全、老旧硬件兼容等实际问题。系统支持模块化扩展与流程自定义,提升了养老服务效率、医护协同水平和住户安全保障,同时为运营决策提供数据支持。文中还提供了关键模块的代码示例,如健康指数算法、任务调度器和日志记录组件。; 适合人群:具备C++编程基础,从事软件开发或系统设计工作1-3年的研发人员,尤其是关注智慧养老、医疗信息系统开发的技术人员。; 使用场景及目标:①学习如何在真实项目中应用C++构建高性能、可扩展的管理系统;②掌握多源数据整合、实时健康监控、任务调度与权限控制等复杂业务的技术实现方案;③了解AI模型在养老场景中的落地方式及系统架构设计思路。; 阅读建议:此资源不仅包含系统架构与模型描述,还附有核心代码片段,建议结合整体设计逻辑深入理解各模块之间的协同机制,并可通过重构或扩展代码来加深对系统工程实践的掌握。
内容概要:本文详细介绍了一个基于C++的城市交通流量数据可视化分析系统的设计与实现。系统涵盖数据采集与预处理、存储与管理、分析建模、可视化展示、系统集成扩展以及数据安全与隐私保护六大核心模块。通过多源异构数据融合、高效存储检索、实时处理分析、高交互性可视化界面及模块化架构设计,实现了对城市交通流量的实时监控、历史趋势分析与智能决策支持。文中还提供了关键模块的C++代码示例,如数据采集、清洗、CSV读写、流量统计、异常检测及基于SFML的柱状图绘制,增强了系统的可实现性与实用性。; 适合人群:具备C++编程基础,熟悉数据结构与算法,有一定项目开发经验的高校学生、研究人员及从事智能交通系统开发的工程师;适合对大数据处理、可视化技术和智慧城市应用感兴趣的技术人员。; 使用场景及目标:①应用于城市交通管理部门,实现交通流量实时监测与拥堵预警;②为市民出行提供路径优化建议;③支持交通政策制定与信号灯配时优化;④作为智慧城市建设中的智能交通子系统,实现与其他城市系统的数据协同。; 阅读建议:建议结合文中代码示例搭建开发环境进行实践,重点关注多线程数据采集、异常检测算法与可视化实现细节;可进一步扩展机器学习模型用于流量预测,并集成真实交通数据源进行系统验证。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值