Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android實現IOS相機滑動控件

Android實現IOS相機滑動控件

編輯:關於Android編程

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的效果,如果有大神有想法,可以指導下。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved