android相机插件,Android实现IOS相机滑动控件

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

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

56e9a53fc7c978f2d5d67eb6f5fd0f7c.gif

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

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,就在上面盖了张图片,显得两边有阴影。

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context="com.example.androidcustomnview.MainActivity" >

android:id="@+id/ViewRoot"

android:gravity="center"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:orientation="horizontal"

android:background="@android:color/background_dark"

android:id="@+id/mCustomView"

android:layout_width="match_parent"

android:layout_height="wrap_content"

>

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"/>

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值