返回顶部
首页 > 资讯 > 移动开发 >Android实现IOS相机滑动控件
  • 369
分享到

Android实现IOS相机滑动控件

IOSAndroid 2022-06-06 07:06:21 369人浏览 独家记忆
摘要

iOS相比于Android,动画效果是一方面优势,ioS相机切换时滑动的动画很不错,看着是有一个3D的效果,而且变化感觉很自然。Android也可以通过Graphics下面的C

iOS相比于Android,动画效果是一方面优势,ioS相机切换时滑动的动画很不错,看着是有一个3D的效果,而且变化感觉很自然。Android也可以通过Graphics下面的Camera可以实现3D效果,开始尝试着用这个做了一下,效果不理想,滑动之后各组文字之间的距离就变了,从立体空间来说这是合逻辑的,但是看着很别捏。IOS相机的滑动效果文字之间的间隔在滑动的时候是不变的。

后面通过调整TextView X方向的scale使文字看着紧凑一点,然后通过计算的距离的方式,在滑动的时候保持各组文字之间的间隔一致,最后实现的效果还是和IOS的有一定的差距。先上个效果图的。 

下面逐步来说下怎么实现:

MainaActivity.java: 

往自定义的控件加了6个TextView,对应各个模式。 

这里面还实现了一个手势监听,来识别滑动事件。对动画做了一些限制,角度小于30度,滑动距离大于15才能生效。 


package com.example.androidcustomnview;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.MotionEvent;
import android.view.TextureView;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationSet;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class MainActivity extends Activity implements OnTouchListener{
 private static final String TAG = "MainActivity.TAG";
 CustomViewL mCustomViewL;
 String[] name = new String[] {"延时摄影","慢动作","视频","拍照","正方形","全景"};
 GestureDetector mGestureDetector;
 RelativeLayout rootView;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mCustomViewL = (CustomViewL) findViewById(R.id.mCustomView);
  rootView = (RelativeLayout) findViewById(R.id.ViewRoot);
  rootView.setOnTouchListener(this);
  mCustomViewL.getParent();
  mCustomViewL.addIndicator(name);
  mGestureDetector = new GestureDetector(this, new myGestureDetectorLis()); 48  }
 class myGestureDetectorLis implements GestureDetector.OnGestureListener {
  private static final int degreeLimit = 30;
  private static final int distanceLimit = 15;
  private boolean isScroll = false;
  @Override
  public boolean onDown(MotionEvent e) {
   // TODO Auto-generated method stub
   Log.d(TAG, "myGestureDetectorLis onDown");
   isScroll = false;
   return true;
  }
  @Override
  public void onShowPress(MotionEvent e) {
   // TODO Auto-generated method stub
  }
  @Override
  public boolean onSingleTapUp(MotionEvent e) {
   // TODO Auto-generated method stub
   return false;
  }
  @Override
  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
    float distanceY) {
   // TODO Auto-generated method stub
   if (isScroll) return false;
   double degree = Math.atan(Math.abs(e2.getY() - e1.getY()) / Math.abs(e2.getX() - e1.getX())) * 180 /Math.PI;
   float delta = e2.getX() - e1.getX();
   if (delta > distanceLimit && degree < degreeLimit) {
    Log.d(TAG, "向右滑");
    isScroll = true;
    mCustomViewL.scrollRight();
   } else if (delta < -distanceLimit && degree < degreeLimit) {
    Log.d(TAG, "向左滑");
    isScroll = true;
    mCustomViewL.scrollLeft();
   }
   return false;
  }
  @Override
  public void onLongPress(MotionEvent e) {
   // TODO Auto-generated method stub
  }
  @Override
  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
    float velocityY) {
   // TODO Auto-generated method stub
   return false;
  }
 }
 @Override
 public boolean onTouch(View v, MotionEvent event) {
  // TODO Auto-generated method stub
  return mGestureDetector.onTouchEvent(event);
 }
}

CustomViewL.java:

自定义的控件,继承自LinearLayout。在onLayout里面,重新计算了下各个子控件的位置,因为各组文字的scale是不一样的,必须重新Layout一下各个子控件的位置,是文字的显示区域和点击区域是一样的,这样给各个子控件设置的onClick事件才有效。

dispatchDraw方法是重绘各个子控件,更具各个子控件到中心控件的位置的距离,设置了各个TextView X方向的scale,为了就是看着要有一个立体的效果。

滑动之后,开始一个动画,动画结束之后重新requestLayout一下,重新计算下各个控件的位置。这个可以连续滑动的,如果这次动画在执行,会保存一下,等动画完了之后会接着跑下一个动画。各个子控件滑动距离的计算有兴趣的可以自己研究下,这里就不赘述了,其实也是数学知识。 


package com.example.androidcustomnview;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;
import android.widget.TextView;
public class CustomViewL extends LinearLayout {
 private static final String TAG = "CustomViewL.TAG";
 private Matrix mMatrix;
 Camera mCamera;
 private int mCurrentItem = 2; 
 private int screenWidth;
 private Paint mPaint;
 public static final float ItemScale = 0.1f;
 public CustomViewL(Context context) {
  super(context);
  // TODO Auto-generated constructor stub
  initView(context);
 }
 public CustomViewL(Context context, AttributeSet attrs, int defStyleAttr,
   int defStyleRes) {
  super(context, attrs, defStyleAttr, defStyleRes);
  initView(context);
 }
 public CustomViewL(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  initView(context);
 }
 public CustomViewL(Context context, AttributeSet attrs) {
  super(context, attrs);
  initView(context);
 }
 private void initView(Context context) {
  screenWidth = ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE))
    .getDefaultDisplay().getWidth();
 }
 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
  Log.d(TAG, "onLayout ");
  super.onLayout(changed, l , t, r, b);
  View v = getChildAt(mCurrentItem);
  int delta = getWidth() / 2 - v.getLeft() - v.getWidth()/2;
  for (int i = 0; i < getChildCount(); i++) {
   View v1 = getChildAt(i);
   if (i == mCurrentItem) {
    v1.layout(v1.getLeft() + delta, v1.getTop(), 
     v1.getRight() + delta, v1.getBottom());
    continue;
   }
   float mScale = Math.abs(i - mCurrentItem) * ItemScale;
   int move = (int)(v1.getWidth() * mScale / 2);
   if (i < mCurrentItem) {
    for (int j = i + 1; j < mCurrentItem; j++) {
     View v2 = getChildAt(j);
     move += (int) (v2.getWidth() * Math.abs(j - mCurrentItem) * ItemScale);
    }
   } else {
    for (int j = i - 1; j > mCurrentItem; j--) {
     View v2 = getChildAt(j);
     move += (int)(v2.getWidth() * Math.abs(j - mCurrentItem) * ItemScale);
    }
    move = -move;
   }
   v1.layout(v1.getLeft() + delta + move, v1.getTop(), 
     v1.getRight() + delta + move, v1.getBottom());
  }
  mRequstLayout = false;
 }
 @Override
 protected void dispatchDraw(Canvas canvas) {
  int count = getChildCount();
  for (int i = 0; i < count; i++) {
   updateChildItem(canvas,i);
  }
 }
 public void updateChildItem(Canvas canvas,int item) {
//  Log.d(TAG, "updateChildItem");
  View v = getChildAt(item);  
  float desi = 1- Math.abs(item - mCurrentItem) * ItemScale;
  ((TextView)v).setScaleX(desi);
  drawChild(canvas, v, getDrawingTime());
  updateTextColor();  
 } 
 private void updateTextColor() {
  for (int i =0 ; i < getChildCount(); i++) {
   if (i == mCurrentItem) {
    ((TextView)getChildAt(i)).setTextColor(Color.YELLOW);
   } else {
    ((TextView)getChildAt(i)).setTextColor(Color.WHITE);
   }
  }
 }  
 boolean scroolToRight = false;
 public void scrollRight() {
  if (mRequstLayout) return;
  if (mCurrentItem > 0) {
   if (mAnimationRunning) {
    if (AnimationRunninGCount < 1) {
     currentItemCopy = mCurrentItem - 1;
     AnimationRunningCount++;
     scroolToRight = true;
    }
    return;
   }
   mCurrentItem--;
   startTraAnimation(mCurrentItem,mCurrentItem + 1);
   updateTextColor();
  }
 }
 private int currentItemCopy;
 public void scrollLeft() {
  if (mRequstLayout) return;
  if (mCurrentItem < getChildCount() - 1) {
   if (mAnimationRunning) {
    if (AnimationRunningCount < 1) {
     currentItemCopy = mCurrentItem + 1;
     AnimationRunningCount++;
     scroolToRight = false;
    }
    return;
   }
   mCurrentItem++;
   startTraAnimation(mCurrentItem,mCurrentItem-1);
   updateTextColor();
  } 
 }
 public void addIndicator(String[] name) {
  for (int i=0; i< name.length; i++) {
   TextView mTextView = new TextView(getContext());
   mTextView.setText(name[i]);
   mTextView.setTextColor(Color.WHITE);
   mTextView.setLines(1);
   LinearLayout.LayoutParams ll = new LinearLayout.LayoutParams(
     LinearLayout.LayoutParams.WRAP_CONTENT, 
     LinearLayout.LayoutParams.WRAP_CONTENT);
   ll.setMargins(20, 0, 20, 0);
   addView(mTextView,ll);
  }
 }
 class myAnimationListener implements android.view.animation.Animation.AnimationListener {
  @Override
  public void onAnimationStart(Animation animation) {
   Log.d(TAG, "onAnimationStart ");
   mAnimationRunning = true;
  }
  @Override
  public void onAnimationEnd(Animation animation) {
   // TODO Auto-generated method stub
   Log.d(TAG, "onAnimationEnd ");
   for (int i= 0; i < getChildCount(); i++) {
    getChildAt(i).clearAnimation();
   }
   mRequstLayout = true;
   requestLayout();
   mAnimationRunning = false;
   if (AnimationRunningCount > 0) {
    CustomViewL.this.post(new Runnable() {
     @Override
     public void run() {
      // TODO Auto-generated method stub
      AnimationRunningCount--;
      mCurrentItem = currentItemCopy;
      int lastItem = scroolToRight ? currentItemCopy + 1 : currentItemCopy - 1;
      startTraAnimation(currentItemCopy,lastItem);
      updateTextColor();
     }
    });
   }
  }
  @Override
  public void onAnimationRepeat(Animation animation) {
  }
 }
 private int AnimitionDurationTime = 300;
 private int AnimationRunningCount = 0;
 private boolean mAnimationRunning = false;
 private boolean mRequstLayout = false;
 public void startTraAnimation(int item,int last) {
  Log.d(TAG, "startTraAnimation item = " + item);
  View v = getChildAt(item);
  final int width = v.getWidth();
  final int childCount = getChildCount();
  int traslate = getWidth()/2 - v.getLeft() - width/2;
  int currentItemWidthScale = (int) (width * ItemScale);
  for (int i = 0; i < childCount; i++) {
   int delta = currentItemWidthScale / 2;   
   Log.d(TAG, " i = " + i + " delta before = " + delta); 
   if (i < item) {
    delta = -delta;
    for (int j = i; j < item; j++) {
     int a;
     if (i == j) {
      a = (int)(getChildAt(j).getWidth() * ItemScale / 2);
     } else {
      a = (int)(getChildAt(j).getWidth() * ItemScale);
     }
     delta = item < last ? delta - a : delta + a;
    }
   } else if (i > item){
    for (int j = item + 1; j <= i; j++) {
     int a;
     if (j == i) {
      a = (int)(getChildAt(j).getWidth() * ItemScale / 2);
     } else {
      a = (int)(getChildAt(j).getWidth() * ItemScale);
     }
     delta = item < last ? delta - a : delta + a;
    }
   } else {
    delta = 0;
   }
   Log.d(TAG, "delta = " + delta);
   delta += traslate;
   TranslateAnimation translateAni = new TranslateAnimation(0, delta, 0, 0);
   translateAni.setDuration(AnimitionDurationTime);
   translateAni.setFillAfter(true);
   if (i == item) translateAni.setAnimationListener(new myAnimationListener());
   mAnimationRunning = true;
   getChildAt(i).startAnimation(translateAni);
  }
 }
}

最后说一下布局文件,两边本来是要做一个阴影效果的,为了简便,复习了下PS,就在上面盖了张图片,显得两边有阴影。  


<RelativeLayout xmlns:android="Http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:context="com.example.androidcustomnview.MainActivity" >
 <RelativeLayout
  android:id="@+id/ViewRoot"
  android:gravity="center" 
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <com.example.androidcustomnview.CustomViewL
   android:orientation="horizontal"
   android:background="@android:color/background_dark"
   android:id="@+id/mCustomView"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   >
  </com.example.androidcustomnview.CustomViewL>
  <ImageView 
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_alignLeft="@id/mCustomView"
   android:layout_alignTop="@id/mCustomView"
   android:layout_alignRight="@id/mCustomView"
   android:layout_alignBottom="@id/mCustomView"
   android:background="@drawable/test"/>
 </RelativeLayout>
</RelativeLayout>

整个来说其实也不复杂,有好些数学计算,几何问题,效果也没达到iphone的效果,如果有大神有想法,可以指导下。

您可能感兴趣的文章:iOS自定义相机实现拍照、录制视频iOS框架AVFoundation实现相机拍照、录制视频iOS仿微信相机拍照、视频录制功能IOS打开照相机与本地相册选择图片实例详解iOS开发-自定义相机实例(仿微信)iOS开发-调用系统相机和相册获取照片示例IOS10 相册相机闪退bug解决办法iOS8调用相机报警告Snapshotting a view的解决方法iOS 10 使用相机相簿闪退的bug修正方法IOS打开系统相机的闪光灯iOS开发技巧之自定义相机


--结束END--

本文标题: Android实现IOS相机滑动控件

本文链接: https://lsjlt.com/news/24449.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Android实现IOS相机滑动控件
    IOS相比于Android,动画效果是一方面优势,IOS相机切换时滑动的动画很不错,看着是有一个3D的效果,而且变化感觉很自然。Android也可以通过Graphics下面的C...
    99+
    2022-06-06
    IOS Android
  • Android实现果冻滑动效果的控件
    前言 在微信是的处理方法是让用户滑动,但最终还是回滚到最初的地方,这样的效果很生动(毕竟成功还是取决于细节)。那么在安卓我们要怎么弄呢。下面为大家介绍一下JellyScroll...
    99+
    2022-06-06
    果冻 动效 Android
  • Android实现滑动选择控件实例代码
    前言 最近做了个滑动选择的小控件,拿出来给大家分享一下,先上图 运行效果 实现步骤 这里分解为3个动作:Down、Move、Up来进行分析,博主文采不好,大家直接看流程图吧...
    99+
    2022-06-06
    选择 Android
  • Android实现小米相机底部滑动指示器
    近期工作内容需要涉及到相机开发,其中一个功能点就是实现一个相机预览页底部的滑动指示器,现在整理出来供大家讨论参考。 先上一张图看下效果: 主要实现功能有: 1.支持左右滑动,每次滑...
    99+
    2024-04-02
  • iOS UICollectionView实现横向滑动
    本文实例为大家分享了iOS UICollectionView实现横向滑动的具体代码,供大家参考,具体内容如下 UICollectionView的横向滚动,目前我使用在了显示输入框的输...
    99+
    2022-05-25
    iOS 滑动
  • Android开发仿IOS滑动开关实现代码
    Android开发仿IOS滑动开关实现代码Android与iOS相比,ios好多控件都是自带的,而android需要使用自定义来实现。今天说的是ios的滑动开关,我层看到好多博客都是通过自定义ToggleButton实现的。这里我通过自定义...
    99+
    2023-05-31
    android ios 滑动开关
  • Android自定义View实现随手势滑动控件
    本文控件为大家分享了Android随手势滑动控件的具体代码,供大家参考,具体内容如下 1.新建自定义控件类:MyView public class MyView extend...
    99+
    2022-06-06
    view 手势 Android
  • Android自定义控件实现滑动开关效果
    自定义开关控件   Android自定义控件一般有三种方式 1、继承Android固有的控件,在Android原生控件的基础上,进行添加功能和逻辑。 2、继承V...
    99+
    2022-06-06
    开关 Android
  • Android怎么实现小米相机底部滑动指示器
    这篇文章给大家分享的是有关Android怎么实现小米相机底部滑动指示器的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。先上一张图看下效果:主要实现功能有:支持左右滑动,每次滑动一个tab支持tab点击,直接跳到对应...
    99+
    2023-06-14
  • iOS实现背景滑动效果
    本文实例为大家分享了iOS实现背景滑动效果的具体代码,供大家参考,具体内容如下 1、在很多APP中,我们都可以看见那些特效绚丽的滑动选项条,那么如何才能够简单,快速的实现那样的效果呢...
    99+
    2024-04-02
  • iOS实现无限滑动效果
    在看到这个标题的时候,相信大家心里肯定会想,无限循环轮播的博客已经满天飞了,好有必要写么。这里我想声明一下,这里的无线滑动,但是数据却不循环。 实现原理 由于业务的需求,需要有大量的...
    99+
    2024-04-02
  • Android自定义控件实现简单滑动开关效果
    本文实例为大家分享了Android自定义控件实现简单滑动开关的具体代码,供大家参考,具体内容如下 ToggleButton 滑动开关 项目概述 滑动开关是一个纯粹的自定义控件,上面的...
    99+
    2024-04-02
  • Android自定义view实现滑动解锁九宫格控件
    目录前言需求效果图前言 上一篇文章用贝塞尔曲线画了一个看起来不错的小红点功能,技术上没什么难度,主要就是数学上的计算。这篇文章也差不多,模仿了一个常用的滑动解锁的九宫格控件。 需求 ...
    99+
    2023-02-09
    Android滑动解锁九宫格 Android滑动解锁 Android九宫格控件
  • 怎么在Android应用中实现㝉滑动选择控件
    这篇文章给大家介绍怎么在Android应用中实现㝉滑动选择控件,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。实现步骤这里分解为3个动作:Down、Move、Up来进行分析,博主文采不好,大家直接看流程图吧!!代码分析前...
    99+
    2023-05-31
    android roi
  • iOS实现垂直滑动条效果
    我们知道在 iOS 开发中,有一个控件经常用到,那就是滑动条(UISlider),可以满足我们滑动取值的需求。但是现在有一个需求,就是需要一个垂直的滑动条,而 UISlider 并不...
    99+
    2024-04-02
  • Android自定义双向滑动控件
    本文实例为大家分享了Android自定义双向滑动控件的具体代码,供大家参考,具体内容如下 先看一下效果图 1.SeekBarPressure工具类 public class See...
    99+
    2024-04-02
  • Android自定义控件实现可左右滑动的导航条
    先上效果图: 这个控件其实算是比较轻量级的,相信不少小伙伴都能做出来。因为项目中遇到了一些特殊的定制要求,所以就自己写了一个,这里放出来。  首先来分析下这个控件的...
    99+
    2022-06-06
    导航条 Android
  • 使用Android自定义控件实现滑动解锁九宫格
    本文概述:  滑动解锁九宫格的分析: 1、需要自定义控件; 2、需要重写事件onTouchEvent(); 3、需要给九个点设置序号和坐标,这里用Map类就行;...
    99+
    2022-06-06
    解锁 Android
  • Android中实现监听ScrollView滑动事件
    时候我们需要监听ScroView的滑动情况,比如滑动了多少距离,是否滑到布局的顶部或者底部。可惜的是SDK并没有相应的方法,不过倒是提供了一个 代码如下: protecte...
    99+
    2022-06-06
    事件 scrollview Android
  • iOS滑动全屏实现返回功能
    本文实例为大家分享了iOS滑动全屏实现返回功能的具体代码,供大家参考,具体内容如下 系统自带的滑动返回功能,只能滑动边缘返回,而我们希望通过滑动全屏实现返回功能。 定义BaseNav...
    99+
    2022-06-02
    iOS 滑动 返回
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作