图片陀螺仪效果:
呃呃,由于博客不能上传视频,只能添加视频链接,我就截张图吧,大家可以下载链家app看下房源详情的首图效果:

实现如下:

加载图片用的Glide:

compile 'com.github.bumptech.glide:glide:4.0.0'
import android.content.Context;
import android.graphics.Canvas;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.ImageView;public class GyroscopeImageView extends ImageView {private double mScaleX;private double mScaleY;private float mLenX;private float mLenY;protected double mAngleX;protected double mAngleY;private float mOffsetX;private float mOffsetY;public GyroscopeImageView(Context context) {super(context);init();}public GyroscopeImageView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);init();}public GyroscopeImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {setScaleType(ScaleType.CENTER);}@Overridepublic void setScaleType(ScaleType scaleType) {super.setScaleType(ScaleType.CENTER);}public float getOffsetX() {return mOffsetX;}public float getOffsetY() {return mOffsetY;}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();GyroscopeManager gyroscopeManager = GyroscopeManager.getInstance();if (gyroscopeManager != null) {gyroscopeManager.addView(this);}}@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();GyroscopeManager gyroscopeManager = GyroscopeManager.getInstance();if (gyroscopeManager != null) {gyroscopeManager.removeView(this);}}public void update(double scaleX, double scaleY) {mScaleX = scaleX;mScaleY = scaleY;invalidate();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();if (getDrawable() != null) {int drawableWidth = getDrawable().getIntrinsicWidth();int drawableHeight = getDrawable().getIntrinsicHeight();mLenX = Math.abs((drawableWidth - width) * 0.5f);mLenY = Math.abs((drawableHeight - height) * 0.5f);}}@Overrideprotected void onDraw(Canvas canvas) {if (getDrawable() == null || isInEditMode()) {super.onDraw(canvas);return;}mOffsetX = (float) (mLenX * mScaleX);mOffsetY = (float) (mLenY * mScaleY);canvas.save();canvas.translate(mOffsetX, mOffsetY);super.onDraw(canvas);canvas.restore();}@Overridepublic boolean equals(Object obj) {return super.equals(obj);}@Overridepublic int hashCode() {return super.hashCode();}
}
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.view.View;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class GyroscopeManager implements SensorEventListener {private static final String TAG = GyroscopeManager.class.getSimpleName();/*** 将纳秒转化为秒*/private static final float NS2S = 1.0f / 1000000000.0f;/*** 维护 GyroscopeImageView 的 状态, 需要传感器处理的 GyroscopeImageView 其对应的 value 为 true*/private Map<GyroscopeImageView, Boolean> mViewsMap = new HashMap<>(9);/*** 维护需要传感器处理的 Activity*/private List<Activity> mActivityList = new ArrayList<>();private SensorManager sensorManager;private long mLastTimestamp;private double mMaxAngle = Math.PI / 2;private GyroscopeManager() {}private static class InstanceHolder {private static final GyroscopeManager sGyroscopeManager = new GyroscopeManager();}public static GyroscopeManager getInstance() {return InstanceHolder.sGyroscopeManager;}protected void addView(GyroscopeImageView gyroscopeImageView) {if (mActivityList.contains(getActivityFromView(gyroscopeImageView))) {mViewsMap.put(gyroscopeImageView, true);} else {mViewsMap.put(gyroscopeImageView, false);}}protected void removeView(GyroscopeImageView gyroscopeImageView) {mViewsMap.remove(gyroscopeImageView);}public void register(Activity activity) {mActivityList.add((activity));for (GyroscopeImageView view : mViewsMap.keySet()) {for (Activity a : mActivityList) {if (getActivityFromView(view) == a) {mViewsMap.put(view, true);}}}if (sensorManager == null) {sensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);}Sensor sensor;if (sensorManager != null) {sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);//灵敏度从快到慢 可选择: SENSOR_DELAY_FASTEST; SENSOR_DELAY_GAME; SENSOR_DELAY_NORMAL; SENSOR_DELAY_UIsensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME);mLastTimestamp = 0;}}public void unregister(Activity activity) {mActivityList.remove((activity));for (GyroscopeImageView view : mViewsMap.keySet()) {if (getActivityFromView(view) == activity) {mViewsMap.put(view, false);}}sensorManager.unregisterListener(this);sensorManager = null;}@Overridepublic void onSensorChanged(SensorEvent event) {if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {if (mLastTimestamp != 0) {for (Map.Entry<GyroscopeImageView, Boolean> entry : mViewsMap.entrySet()) {//只处理集合中 value 为 true 的 viewif (entry.getValue()) {entry.getKey().mAngleX +=event.values[0] * (event.timestamp - mLastTimestamp) * NS2S * 2.0f;entry.getKey().mAngleY +=event.values[1] * (event.timestamp - mLastTimestamp) * NS2S * 2.0f;if (entry.getKey().mAngleX > mMaxAngle) {entry.getKey().mAngleX = mMaxAngle;}if (entry.getKey().mAngleX < -mMaxAngle) {entry.getKey().mAngleX = -mMaxAngle;}if (entry.getKey().mAngleY > mMaxAngle) {entry.getKey().mAngleY = mMaxAngle;}if (entry.getKey().mAngleY < -mMaxAngle) {entry.getKey().mAngleY = -mMaxAngle;}entry.getKey().update(entry.getKey().mAngleY / mMaxAngle, entry.getKey().mAngleX / mMaxAngle);}}}mLastTimestamp = event.timestamp;}}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {}private Activity getActivityFromView(View view) {if (view.getContext() instanceof Activity){return (Activity) view.getContext();}return null;}
}
import android.graphics.Bitmap;import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
import com.bumptech.glide.load.resource.bitmap.TransformationUtils;import java.security.MessageDigest;public class GyrBitmapFormation extends BitmapTransformation {private int mWidgetWidth;   //控件宽度private int mWidgetHeight;  //控件高度private double mTargetWidth;    //目标宽度private double mTargetHeight;   //目标高度public GyrBitmapFormation(int mWidgetWidth, int mWidgetHeight) {this.mWidgetWidth = mWidgetWidth;this.mWidgetHeight = mWidgetHeight;}@Overrideprotected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {if (toTransform.getWidth() == 0 || toTransform.getHeight() == 0) {return toTransform;}//compile 'com.github.bumptech.glide:glide:4.0.0'//这里的方法根据glide的4.X的需要TransformationUtils.centerCrop转化,3.X的source直接用toTransform就可以Bitmap source = TransformationUtils.centerCrop( pool, toTransform, outWidth, outHeight);mTargetWidth = source.getWidth();mTargetHeight = source.getHeight();double ratio = mTargetWidth / mTargetHeight;     //图片的宽高比int distance;                                    //图片缩放后与控件边的距离if (mWidgetHeight <= mWidgetWidth) {distance = mWidgetHeight / 8;mTargetWidth = mWidgetWidth + 2 * distance;mTargetHeight = mTargetWidth / ratio;} else {distance = mWidgetWidth / 8;mTargetHeight = mWidgetHeight + 2 * distance;mTargetWidth = mTargetHeight * ratio;}int desiredWidth = (int) mTargetWidth;int desiredHeight = (int) mTargetHeight;Bitmap result = Bitmap.createScaledBitmap(source, desiredWidth, desiredHeight, false);if (result != source) {// Same bitmap is returned if sizes are the samesource.recycle();}return result;}@Overridepublic void updateDiskCacheKey(MessageDigest messageDigest) {}
}

调用方式:

import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;import gyroscope.GyrBitmapFormation;
import gyroscope.GyroscopeImageView;
import gyroscope.GyroscopeManager;public class GyroscopeActivity extends Activity {String url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1600250532949&di=26b9776fd0bfc21eaa9fc51710983ca5&imgtype=0&src=http%3A%2F%2Fbjcache.leju.com%2Fzxjiaju%2Fzx_pic%2F20150227%2F45%2Fd2%2F4d256df8f863c0dd622b9685887eb357.png";private GyroscopeImageView giv;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_gyroscope);giv = findViewById(R.id.giv);giv.post(new Runnable() {@Overridepublic void run() {//获取控件大小,作为拉伸参数int width = giv.getWidth();int height = giv.getHeight();RequestOptions options = new RequestOptions();options.transform(new GyrBitmapFormation(width, height));Glide.with(GyroscopeActivity.this).load(url).apply(options).into(giv);}});}//记得注册和反注册 传感器@Override protected void onResume() {super.onResume();GyroscopeManager.getInstance().register(this);}@Override protected void onPause() {super.onPause();GyroscopeManager.getInstance().unregister(this);}
}

activity_gyroscope布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><gyroscope.GyroscopeImageViewandroid:id="@+id/giv"android:layout_width="match_parent"android:layout_height="240dp"/>
</LinearLayout>

原理:
获取图片控件View大小,再将图片根据控件View大小放大一定比例,通过陀螺仪传感器的数据变化来实时平移刷新图片。这样通过旋转手机屏幕,能看到动态的图片。

大神的demo

Android 图片陀螺仪效果/VR效果-仿链家、贝壳相关推荐

  1. 仿链家地图找房_全网稀缺,完整链家地图找房的实现(一)

    前一段时间我应公司的需求开发了类似链家地图找房的功能,然而我发现现在市面上,对于链家地图找房功能的完整实现相关的文章还是比较稀缺的,亦或是功能还不够完善,出于这个方面,我觉得把自己对于链家地图找房功能 ...

  2. 仿链家地图找房的简单实现 1

    本篇目录: 使用入门 简单使用流程 链家地图找房效果 区域点位气泡 数据结构 实现 addOverlay方法 区域边界 获取区域点位经纬度 获取区域边界 小结 最近由于项目需要,开始调研如何使用百度地 ...

  3. Android 图片Loading旋转动画效果

    使用场景:在数据请求或者一些加载的页面中,总需要一些过度的动画效果,很多时候我们都可以在图片中间加一个loading的旋转图片,以前也做过,今天做的时候噼里啪啦敲了半天结果运行没效果,所以今天总结下这 ...

  4. android图片跳转动画效果,Android实现Activity界面切换添加动画特效的方法

    本文以实例形式展示了Android实现Activity界面切换添加动画特效的方法,对于Android程序设计人员来说有很好的参考借鉴价值.具体方法如下: 了解Android程序设计的人应该知道,在An ...

  5. 仿链家地图找房_我在深圳的第一个家 是在有着6000套房的工业区里

    https://www.zhihu.com/video/1098548661679751168 张 佳荣 / 互联网公司员工 临近毕业,我决定要留在深圳 找房那天,晴空万里 Ⅰ 初 见 集 悦 城 大 ...

  6. iOS 仿链家筛选(单选、多选、滑动筛选联动、多表联动)

    目前市场上很多应用都包含了筛选功能,自己写了个demo给大家分享一下,共同学习,共同进步 Demo传送门 先说说常见的collectionView多选功 - (void)collectionView: ...

  7. thinkphp多城市房产系统源码程序_Thinkphp5.0内核开发房产网门户系统源码tp5Fangcms仿链家源码模板多城市版...

    fangcms2017v1.0多城市版站群版多站点房产网站源码房地产网站,,Thinkphp5多城市房产系统开源源码带房产系统数据字典.房产系统二次开发手册和房产系统安装说明. www.tz365.C ...

  8. 基于SpringBoot+vue的高仿链家租房平台

    项目架构 SpringBoot-2.2.0 vue vue-Baidu-map elasticsearch-6.2.1 Redis 企业微信API 阿里云oss 主要功能 门户端[pc端和移动端]: ...

  9. Android VR效果实现

    最终效果预览 解决的问题 实现iOS锁屏界面壁纸随传感器运动效果 全景看房图片随传感器运动效果 VR效果的实现 以下效果是跟随手机晃动进行的 思路分析 需要实现的点: 1.图片的左右上下移动 2.旋转 ...

最新文章

  1. 1步轻松修改Jupyter Notebook默认的工作目录
  2. linux虚拟终端快捷键
  3. JavaScript基础——处理字符串
  4. 【bzoj3280】小R的烦恼 费用流
  5. Java IO流学习总结八:Commons IO 2.5-IOUtils
  6. ios不行安卓可以 微信签名_王者荣耀安卓、iOS互通来了!现在可以互看好友资料...
  7. centos 7新机使用前操作
  8. Liunx配置网络到nginx环境搭建步骤
  9. 匹配追踪分解 时频 matlab,Matlab匹配追踪(MatchingPursuit) 之一
  10. 配置SCCM 2012 SP1(七)操作系统部署
  11. 【报告分享】2020年小红书内容生态报告.pdf(附下载链接)
  12. C++进阶教程之模板
  13. osea/ 5.0-6.0
  14. JSON转Model内部实现解析
  15. (8)Python_分割numpy数组
  16. 小学计算机京剧脸谱教案,京剧脸谱小学高年级美术教学设计
  17. BLM业务战略规划的底层逻辑是什么?
  18. 奈奎斯特第一定律码间串扰
  19. Android中可展开的列表组件(ExpandableListView)的使用
  20. 单肩包属于什么类目_包包属于什么商标类目

热门文章

  1. git 提交命令(附加git常用命令)
  2. 多线程实现方式---实现Runnable接口
  3. 输出如下图案,请填空完成程序。j,n输入答案函数图案题目图片.
  4. F006-与无政资谭叔的对答 #F580
  5. 什么软件可以测试对方把你电话拉黑,不打扰对方,如何检测微信里有没有人把你拉黑?教你一招!...
  6. JavaScript遍历一个table的tr
  7. 一份12W+字数的踩坑总结,覆盖前端、后端、运维三个维度,一步一个脚印,我们一起成长!(实时更新)
  8. Excel删除重复值方法总结(二)
  9. 计算机专业的男生喜欢你,【男生这十个反应说明他喜欢你】_男人的10个表现说明他喜欢上了你...
  10. python用turtle画四叶草_Python turtle画图库画姓名实例