高仿墨迹天气下拉拉伸图片

简介

最近比较闲,就多学习了下,关键是不看点东西,就犯困啊。墨迹天气这个应用有不少地方需要学习的,这篇文章呢, 说一下他的“我”Tab页下拉拉伸图片展示效果,如果留意的话, 像QQ的好友动态也有差不多的效果。

代码分析

代码比较简单了,就重写了一个ScrollView类,先说说他的原理吧,我是先根据id拿到这个ImageView,然后获得他的TopMargin也就是遮掩后的偏移值,在触摸的时候,对ImageView的TopMargin进行改变产生效果,松手的时候搞个属性动画让他还原到以前的位置就Ok了。好了。 原理就是这样了。

先看看布局xml吧

<com.wjj.imagepull.PullScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="@android:color/white"
    android:id="@+id/scroll_view"
    android:scrollbars="none"
    android:layout_height="match_parent">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/pull_img"
                android:layout_marginTop="-50dp"
                android:src="@drawable/personal_back"
                android:layout_width="match_parent"
                android:scaleType="fitXY"
                android:layout_height="250dp" />

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/feed_fengfeng"
                android:scaleType="fitXY"
                android:layout_centerInParent="true" />
        </RelativeLayout>
//此处省略......
    </LinearLayout>
</com.wjj.imagepull.PullScrollView>

大家看到这个设置了吧android:layout_marginTop="-50dp"这个就是要遮掩的多少了,还有这个android:id="@+id/pull_img"  这个id,别乱改了, 我就是根据这个来拿的这个ImageView的。

上代码了

public class PullScrollView extends ScrollView implements ViewTreeObserver.OnGlobalLayoutListener {

    View view;
    int srcTopMargion;
    float lastY;
    float offsetY;

    public PullScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        ViewTreeObserver observer = getViewTreeObserver();
        if (null != observer)
            observer.addOnGlobalLayoutListener(this);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        view = findViewById(R.id.pull_img);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        float y = ev.getY();
        Log.d("onTouchEvent", "action=" + action + ",y=" + y);
        MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //计算滑动y方向偏移值
                offsetY = y - lastY;
                //向下移动
                if (offsetY > 0) {
                    //滑动到看到所有图片展示,交给原来的逻辑处理
                    if (params.topMargin == 0) {
                        return super.onTouchEvent(ev);
                    }
                    //在不是下拉图片的时候,向下移动,交给原来的逻辑处理
                    if (getScrollY() != 0) {
                        return super.onTouchEvent(ev);
                    }
                    //可以下拉图片的情况
                    params.topMargin += offsetY / 10;
                    Log.d("onTouchEvent", "topMargin" + params.topMargin + ",lastY=" + lastY + ",y=" + y + ",offsetY" + offsetY);
                    if (params.topMargin >= 0) {
                        params.topMargin = 0;
                    }
                    view.setLayoutParams(params);
                    invalidate();
                }
                lastY = y;
                break;
            case MotionEvent.ACTION_UP:
                //不和原始margion偏移一样的时候
                if (params.topMargin != -srcTopMargion) {
                    Log.d("ACTION_UP", "moveY=" + (srcTopMargion + params.topMargin));
                    //滚动原始偏移值和现在偏移值之间的差值 eg:3~10
                    ObjectAnimator animator = ObjectAnimator.ofInt(this, "moveY", params.topMargin, -srcTopMargion);
                    animator.setDuration(200);
                    animator.setInterpolator(new LinearInterpolator());
                    animator.start();
                }
                break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 设置移动中的Y值
     *
     * @param value
     */
    public void setMoveY(int value) {
        MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
        params.topMargin = value;
        Log.d("computeScroll", "topMargin=" + params.topMargin);
        view.setLayoutParams(params);
        invalidate();
    }

    @Override
    public void onGlobalLayout() {
        MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
        srcTopMargion = -params.topMargin;
        Log.d("srcTopMargion", "" + srcTopMargion);
        getViewTreeObserver()
                .removeGlobalOnLayoutListener(this);
    }
}

在PullScrollView构造方法里面注册了OnGlobalLayoutListener来监听Tree树改变后的回调,用来获取ImageView的topMargin作为以后还原的目标值,在onFinishInflate里面获取这个view,view = findViewById(R.id.pull_img);

onTouchEvent就是我们的主战场了, 逻辑都在这了,先判断在ACTION_MOVE中,是不是向下滑动,如果是的话,有2种情况是需要排除的, 就是不进行topMargin改变的,是哪些呢?

第一个是topMargin都滑到0了, 就不要滑了吧。

第二个是在其他地方滑动的时候,举个例子吧,就是正常的往下滑的时候,不做处理。

除了这2种情况,下面就是topMargin的改变了,这里我加了一个offsetY / 10的除以10的阻值,就是防止滑的太快了, 这个你可以进行自定义的。

当我抬手的时候,假如说我的topMargin和以前的初始值不一样的时候,还记得吧,咱们在onGlobalLayout取得的那个值,需要做的就是启动一个动画平移滑动到上面了。

当自动滑动的时候,这里用了ObjectAnimator属性动画,其实当时用的是Scroll,为什么又不用他了呢,因为重写的computeScroll方法,如果在里面处理的话,会和自己的滚动有冲突,感兴趣的可以试试。

还有一个setMoveY方法,这个就是属性动画调用的那个方法了,根据线性插值计算后返回的值,然后在用于改变topMargin,直到恢复到刚开始的状态。

结束语

好了,这个项目就算完了,不过我只在我的小米手机上测试了一下,其他分辨率不知道会不会有问题,大家可以测测看。

Github地址

https://github.com/wu928320442/ImagePull

时间: 2024-10-05 23:47:47

高仿墨迹天气下拉拉伸图片的相关文章

高仿墨迹天气黄历

本项目是高仿墨迹天气的黄历功能模块,可插件化安装

高仿墨迹天气 白天晴天

简介 一直对墨迹天气的绚丽的场景蛮感兴趣的,趁有时间,自己就高仿了其中的一个场景,其他场景呢,也是类似的,主要是写对象的AI也就是逻辑了. 先看看效果吧,动态效果比较坑,太模糊 高清图 代码分析 来看看代码结构吧 这里使用了SurfaceView而不是用的view,其实这个天气的场景绘制更像是游戏开发,使用SurfaceView会更灵活. public SceneSurfaceView(Context context, AttributeSet attrs) { super(context, a

安卓开发之Kotlin和java双实现仿qq空间下拉图片拉伸

先不扯淡看今天要实现的效果: 话说使用Kotlin实现安卓功能,那我们还是要做一点准备工作,so,你得加一点插件到eclipse或android studio.然并卵,你现在还在使用eclipse开发的话我只能提供地址Kotlin Plugin for Eclipse,然后我使用的还是死丢丢. 死丢丢(android studio)集成kotlin安卓开发 要使用android studio开发kotlin的安卓app,那么你必须有开发kotlin的环境: Kotlin插件.打开Android

360浏览器搜索框下拉选择图片js模拟select效果

最近360浏览器网址导航的主页增加了一个下拉选择图片搜索的功能,也就是用js模拟出了select的效果,今天在单位闲了无事干,就把空上功能给摸索出来了,虽然做的不是太完善,但对要求不高的用户来说,已经可以了,而且也可以为学习Js的朋友提供参考. <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <style>

Android应用源码之仿墨迹天气插件

Android应用源码之仿墨迹天气插件 仿照墨迹天气的桌面小插件例子源码. 下载地址:http://www.dwz.cn/Cox82 运行截图:

Android仿苹果版QQ下拉刷新实现(一) ——打造简单平滑的通用下拉刷新控件

前言: 因为公司人员变动原因,导致了博主四个月没有动安卓,一直在做IOS开发,如今接近年前,终于可以花一定的时间放在安卓上了.好了,废话不多说,今天我们要带来的效果是苹果版本的QQ下拉刷新.首先看一下目标效果以及demo效果:      因为此效果实现的步骤较多,所以今天博主要实现以上效果的第一步——打造一个通用的下拉刷新控件,具体效果如下: GIF图片比较大,还希望读者能耐心等待一下下从效果图中可以看出,我们的下拉刷新的滑动还是很流畅的,可能大多数开发者用的是XListview或者PullTo

Android 打造自己的个性化应用(四):仿墨迹天气实现--&gt;自定义扩展名的zip格式的皮肤

在这里谈一下墨迹天气的换肤实现方式,不过首先声明我只是通过反编译以及参考了一些网上其他资料的方式推测出的换肤原理, 在这里只供参考. 若大家有更好的方式, 欢迎交流. 墨迹天气下载的皮肤就是一个zip格式的压缩包,在应用的时候把皮肤资源释放到墨迹天气应用的目录下,更换皮肤时新的皮肤资源会替换掉老的皮肤资源每次加载的时候就是从手机硬盘上读取图片,这些图片资源的命名和程序中的资源的命名保持一致,一旦找不到这些资源,可以选择到系统默认中查找.这种实现是直接读取了外部资源文件,在程序运行时通过代码显示的

Android自定义控制(五)仿新浪微博的下拉刷新

网上有很多很有名的开源框架,这里就来拉拉PullToRefresh这个框架,也就是我们平时用的下拉刷新啦,当然你问我这个有什么用啊?别人已经写好了,这里主要是学习以及练习,练习的次数多了,一切就顺其自然的会了. 废话少说,先上图,再上代码: 1.要想实现下拉刷新功能必须要有个下拉刷新的布局,是吧? <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="htt

Android 轻松实现仿QQ空间下拉刷新

(本文讲解了在Android中实现列表下拉刷新的动态效果的过程,文末附有源码.) 看完本文,您可以学到: 1.下拉刷新的实现原理 2.自定义Android控件,重写其ListView 3.ScrollListener滚动监听 4.Adapter适配器的使用 话不多说,先来看看效果图: 接下来我们一步一步地实现以上的效果. 一.图文并茂的ListViewItem 看一下这一步的效果图: 首先,我们要实现的是带下拉刷新效果的ListView.所以我们选择自己重写原生控件ListView.只需要写一个