zoukankan      html  css  js  c++  java
  • Android 实现 IOS相机滑动控件

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

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

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

      MainaActivity.java:

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

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

      1 package com.example.androidcustomnview;
      2 
      3 import android.app.Activity;
      4 import android.graphics.Color;
      5 import android.os.Bundle;
      6 import android.util.Log;
      7 import android.view.GestureDetector;
      8 import android.view.GestureDetector.OnGestureListener;
      9 import android.view.View;
     10 import android.view.View.OnTouchListener;
     11 import android.view.MotionEvent;
     12 import android.view.TextureView;
     13 import android.view.ViewGroup;
     14 import android.view.animation.Animation;
     15 import android.view.animation.Animation.AnimationListener;
     16 import android.view.animation.AnimationSet;
     17 import android.view.animation.TranslateAnimation;
     18 import android.widget.FrameLayout;
     19 import android.widget.LinearLayout;
     20 import android.widget.RelativeLayout;
     21 import android.widget.TextView;
     22 
     23 public class MainActivity extends Activity  implements OnTouchListener{
     24 
     25     private static final String TAG = "MainActivity.TAG";
     26     CustomViewL mCustomViewL;
     27     String[] name = new String[] {"延时摄影","慢动作","视频","拍照","正方形","全景"};
     28 
     29     GestureDetector mGestureDetector;
     30     RelativeLayout rootView;
     31     @Override
     32     protected void onCreate(Bundle savedInstanceState) {
     33         super.onCreate(savedInstanceState);
     34         setContentView(R.layout.activity_main);
     35         mCustomViewL = (CustomViewL) findViewById(R.id.mCustomView);
     36         rootView = (RelativeLayout) findViewById(R.id.ViewRoot);
     37         rootView.setOnTouchListener(this);
     38         mCustomViewL.getParent();
     39         mCustomViewL.addIndicator(name);
     40         mGestureDetector = new GestureDetector(this, new myGestureDetectorLis()); 48     }
     49     
     50     class myGestureDetectorLis implements GestureDetector.OnGestureListener {
     51         
     52         private static final int degreeLimit = 30;
     53         private static final int distanceLimit = 15;
     54         
     55         private boolean isScroll = false;
     56         @Override
     57         public boolean onDown(MotionEvent e) {
     58             // TODO Auto-generated method stub
     59             Log.d(TAG, "myGestureDetectorLis onDown");
     60             isScroll = false;
     61             return true;
     62         }
     63         @Override
     64         public void onShowPress(MotionEvent e) {
     65             // TODO Auto-generated method stub
     66             
     67         }
     68         @Override
     69         public boolean onSingleTapUp(MotionEvent e) {
     70             // TODO Auto-generated method stub
     71             return false;
     72         }
     73         
     74         @Override
     75         public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
     76                 float distanceY) {
     77             // TODO Auto-generated method stub
     78             if (isScroll) return false;
     79             double degree = Math.atan(Math.abs(e2.getY() - e1.getY()) / Math.abs(e2.getX() - e1.getX())) * 180 /Math.PI;
     80             float delta = e2.getX() - e1.getX();
     81             if (delta > distanceLimit && degree < degreeLimit) {
     82                 Log.d(TAG, "向右滑");
     83                 isScroll = true;
     84                 mCustomViewL.scrollRight();
     85             } else if (delta < -distanceLimit && degree < degreeLimit) {
     86                 Log.d(TAG, "向左滑");
     87                 isScroll = true;
     88                 mCustomViewL.scrollLeft();
     89             }
     90             return false;
     91         }
     92         
     93         @Override
     94         public void onLongPress(MotionEvent e) {
     95             // TODO Auto-generated method stub
     96             
     97         }
     98         @Override
     99         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
    100                 float velocityY) {
    101             // TODO Auto-generated method stub
    102             return false;
    103         }
    104         
    105     }
    106 
    107     @Override
    108     public boolean onTouch(View v, MotionEvent event) {
    109         // TODO Auto-generated method stub
    110         return mGestureDetector.onTouchEvent(event);
    111     }
    112 
    113 
    114 }

    CustomViewL.java:

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

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

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

      1 package com.example.androidcustomnview;
      2 
      3 import android.content.Context;
      4 import android.graphics.Camera;
      5 import android.graphics.Canvas;
      6 import android.graphics.Color;
      7 import android.graphics.LinearGradient;
      8 import android.graphics.Matrix;
      9 import android.graphics.Paint;
     10 import android.graphics.Shader;
     11 import android.os.Handler;
     12 import android.os.Message;
     13 import android.util.AttributeSet;
     14 import android.util.Log;
     15 import android.view.MotionEvent;
     16 import android.view.View;
     17 import android.view.WindowManager;
     18 import android.view.animation.Animation;
     19 import android.view.animation.Animation.AnimationListener;
     20 import android.view.animation.TranslateAnimation;
     21 import android.widget.LinearLayout;
     22 import android.widget.TextView;
     23 
     24 public class CustomViewL extends LinearLayout {
     25 
     26     private static final String TAG = "CustomViewL.TAG";
     27     private Matrix mMatrix;
     28     Camera mCamera;
     29     private int mCurrentItem = 2;    
     30     private int screenWidth;
     31     private Paint mPaint;
     32 
     33     public static final float ItemScale = 0.1f;
     34 
     35     public CustomViewL(Context context) {
     36         super(context);
     37         // TODO Auto-generated constructor stub
     38         initView(context);
     39     }
     40     
     41     public CustomViewL(Context context, AttributeSet attrs, int defStyleAttr,
     42             int defStyleRes) {
     43         super(context, attrs, defStyleAttr, defStyleRes);
     44         initView(context);
     45     }
     46 
     47     public CustomViewL(Context context, AttributeSet attrs, int defStyleAttr) {
     48         super(context, attrs, defStyleAttr);
     49         initView(context);
     50     }
     51 
     52     public CustomViewL(Context context, AttributeSet attrs) {
     53         super(context, attrs);
     54         initView(context);
     55     }
     56     
     57     private void initView(Context context) {
     60         screenWidth = ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE))
     61                 .getDefaultDisplay().getWidth();
     63     }
     64     
     65     @Override
     66     protected void onLayout(boolean changed, int l, int t, int r, int b) {
     67         Log.d(TAG, "onLayout ");
     68         super.onLayout(changed, l , t, r, b);
     69         View v = getChildAt(mCurrentItem);
     70         int delta = getWidth() / 2 - v.getLeft() - v.getWidth()/2;
     71          
     72         for (int i = 0; i < getChildCount(); i++) {
     73             View v1 = getChildAt(i);
     74             if (i == mCurrentItem) {
     75                 v1.layout(v1.getLeft() + delta, v1.getTop(), 
     76                     v1.getRight() + delta, v1.getBottom());
     77                 continue;
     78             }
     79             float mScale = Math.abs(i - mCurrentItem) * ItemScale;
     80             int move = (int)(v1.getWidth() * mScale / 2);
     81             if (i < mCurrentItem) {
     82                 for (int j = i + 1; j < mCurrentItem; j++) {
     83                     View v2 = getChildAt(j);
     84                     move += (int) (v2.getWidth() * Math.abs(j - mCurrentItem) * ItemScale);
     85                 }
     86             } else {
     87                 for (int j = i - 1; j > mCurrentItem; j--) {
     88                     View v2 = getChildAt(j);
     89                     move += (int)(v2.getWidth() * Math.abs(j - mCurrentItem) * ItemScale);
     90                 }
     91                 move = -move;
     92             }
     93             v1.layout(v1.getLeft() + delta + move, v1.getTop(), 
     94                     v1.getRight() + delta + move, v1.getBottom());
     95         }
     96         mRequstLayout = false;
     97     }
     98 
     99     @Override
    100     protected void dispatchDraw(Canvas canvas) {
    101         int count = getChildCount();
    102         for (int i = 0; i < count; i++) {
    103             updateChildItem(canvas,i);
    104         }
    105     }
    106     
    107     public void updateChildItem(Canvas canvas,int item) {
    108 //        Log.d(TAG, "updateChildItem");
    110         View v = getChildAt(item);        
    111         float desi = 1- Math.abs(item - mCurrentItem) * ItemScale;
    112         ((TextView)v).setScaleX(desi);
    113         drawChild(canvas, v, getDrawingTime());
    114         updateTextColor();        
    115     }    
    118     private void updateTextColor() {
    119         for (int i =0 ; i < getChildCount(); i++) {
    120             if (i == mCurrentItem) {
    121                 ((TextView)getChildAt(i)).setTextColor(Color.YELLOW);
    122             } else {
    123                 ((TextView)getChildAt(i)).setTextColor(Color.WHITE);
    124             }
    125         }
    126     }     
    128     boolean scroolToRight = false;
    129     
    130     public void scrollRight() {
    131         if (mRequstLayout) return;
    132         if (mCurrentItem > 0) {
    133             if (mAnimationRunning) {
    134                 if (AnimationRunningCount < 1) {
    135                     currentItemCopy = mCurrentItem - 1;
    136                     AnimationRunningCount++;
    137                     scroolToRight = true;
    138                 }
    139                 return;
    140             }
    141             mCurrentItem--;
    142             startTraAnimation(mCurrentItem,mCurrentItem + 1);
    143             updateTextColor();
    144         }
    145     }
    146     
    147     private int currentItemCopy;
    148     public void scrollLeft() {
    149         if (mRequstLayout) return;
    150         if (mCurrentItem < getChildCount() - 1) {
    151             if (mAnimationRunning) {
    152                 if (AnimationRunningCount < 1) {
    153                     currentItemCopy = mCurrentItem + 1;
    154                     AnimationRunningCount++;
    155                     scroolToRight = false;
    156                 }
    157                 return;
    158             }
    159             mCurrentItem++;
    160             startTraAnimation(mCurrentItem,mCurrentItem-1);
    161             updateTextColor();
    162         }    
    163     }
    164     
    165     public void addIndicator(String[] name) {
    166         for (int i=0; i< name.length; i++) {
    167             TextView mTextView = new TextView(getContext());
    168             mTextView.setText(name[i]);
    169             mTextView.setTextColor(Color.WHITE);
    170             mTextView.setLines(1);
    171             LinearLayout.LayoutParams ll = new LinearLayout.LayoutParams(
    172                     LinearLayout.LayoutParams.WRAP_CONTENT, 
    173                     LinearLayout.LayoutParams.WRAP_CONTENT);
    174             ll.setMargins(20, 0, 20, 0);
    175             addView(mTextView,ll);
    176         }
    177     }
    178     
    179     class myAnimationListener implements android.view.animation.Animation.AnimationListener {
    180 
    181         @Override
    182         public void onAnimationStart(Animation animation) {
    183             Log.d(TAG, "onAnimationStart ");
    184             mAnimationRunning = true;
    185         }
    186         @Override
    187         public void onAnimationEnd(Animation animation) {
    188             // TODO Auto-generated method stub
    189             Log.d(TAG, "onAnimationEnd ");
    190 
    191             for (int i= 0; i < getChildCount(); i++) {
    192                 getChildAt(i).clearAnimation();
    193             }
    194             mRequstLayout = true;
    195             requestLayout();
    196             mAnimationRunning = false;
    197             if (AnimationRunningCount > 0) {
    198                 CustomViewL.this.post(new Runnable() {
    199                     @Override
    200                     public void run() {
    201                         // TODO Auto-generated method stub
    202                         AnimationRunningCount--;
    203                         mCurrentItem = currentItemCopy;
    204                         int lastItem = scroolToRight ? currentItemCopy + 1 : currentItemCopy - 1;
    205                         startTraAnimation(currentItemCopy,lastItem);
    206                         updateTextColor();
    207                     }
    208                 });
    209             }
    210         }
    211         @Override
    212         public void onAnimationRepeat(Animation animation) {
    213         }
    214         
    215     }
    216     
    217     private int AnimitionDurationTime = 300;
    218     private int AnimationRunningCount = 0;
    219     private boolean mAnimationRunning = false;
    220     private boolean mRequstLayout = false;
    221     public void startTraAnimation(int item,int last) {
    222         Log.d(TAG, "startTraAnimation item = " + item);
    223         View v = getChildAt(item);
    224         final int width = v.getWidth();
    225         final int childCount = getChildCount();
    226         int traslate = getWidth()/2 - v.getLeft() - width/2;
    227         
    228         int currentItemWidthScale = (int) (width * ItemScale);
    229 
    230         for (int i = 0; i < childCount; i++) {
    231             int delta = currentItemWidthScale / 2;            
    233             Log.d(TAG, " i = " + i + "  delta before = " + delta);    
    234             if (i < item) {
    235                 delta = -delta;
    236                 for (int j = i; j < item; j++) {
    237                     int a;
    238                     if (i == j) {
    239                         a = (int)(getChildAt(j).getWidth() * ItemScale / 2);
    240                     } else {
    241                         a = (int)(getChildAt(j).getWidth() * ItemScale);
    242                     }
    243                     delta = item < last ? delta - a : delta + a;
    244                 }
    245             } else if (i > item){
    246                 for (int j = item + 1; j <= i; j++) {
    247                     int a;
    248                     if (j == i) {
    249                         a = (int)(getChildAt(j).getWidth() * ItemScale / 2);
    250                     } else {
    251                         a = (int)(getChildAt(j).getWidth() * ItemScale);
    252                     }
    253                     delta = item < last ? delta - a : delta + a;
    254                 }
    255             } else {
    256                 delta = 0;
    257             }
    258             Log.d(TAG, "delta  = " + delta);
    259             delta += traslate;
    260             TranslateAnimation translateAni = new TranslateAnimation(0, delta, 0, 0);
    261             translateAni.setDuration(AnimitionDurationTime);
    262             translateAni.setFillAfter(true);
    263             if (i == item) translateAni.setAnimationListener(new myAnimationListener());
    264             mAnimationRunning = true;
    265             getChildAt(i).startAnimation(translateAni);
    266         }
    268     }
    269 }

     最后说一下布局文件,两边本来是要做一个阴影效果的,为了简便,复习了下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的效果,如果有大神有想法,可以指导下。

  • 相关阅读:
    从安装.net Core 到helloWord(Mac上)
    阿里云-对象储存OSS
    图片处理
    项目中 添加 swift代码 真机调试 错误
    iOS面试总结
    IOS APP配置.plist汇总
    cocoapods安装问题
    iOS8使用UIVisualEffectView实现模糊效果
    ios键盘回收终极版
    ?C++ 缺少参数的默认参数
  • 原文地址:https://www.cnblogs.com/xiaojianli/p/5689480.html
Copyright © 2011-2022 走看看