打造一款有趣的Android万能播放器之扇形动画菜单+自由拖拽图标+3D图片滑动倾斜放大倒影+自定义scrollview实现滑动监听

项目初衷

由于所在的公司比较注重项目安全性,所以在项目同步这块几乎没有涉足,乘工作之余敲一个简单的app,起名为EasyLive,目的于熟悉一些工作之外的有趣知识点和巩固自己的基础知识。

项目内容

以打造一款兼容性较为完整的android万能播放器为基础,后期再不断的添加一些生活中有趣的功能点,并不定期的将项目同步到github上,以供大家共同修改和指教。

目录

集成准备------------------------------------------------------------------------------1
前端UI设计---------------------------------------------------------------------------2
动画菜单、图标拖拽、图片滑动、自定义scrollview等模块处理--------3

项目框架说明图

习惯性的用eclipse,不知道是自己真的老了,还是eclipse打包出来的apk总是比AS小的原因,需要AS源码的朋友记得Q我哈,或者来个大神直接贡献到git上与我们一起分享(地址)。

自定义scrollview实现滑动监听(伤陌1991

package com.minghui.easyapp.scrollview;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;

public class ObserveScrollView extends ScrollView {

	private ScrollListener mListener;

	public static interface ScrollListener {// 声明接口,用于传递数据
		public void scrollOritention(int l, int t, int oldl, int oldt);
	}

	public ObserveScrollView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
	}

	public ObserveScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	public ObserveScrollView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	@Override
	protected void onScrollChanged(int l, int t, int oldl, int oldt) {
		// TODO Auto-generated method stub
		super.onScrollChanged(l, t, oldl, oldt);
		if (mListener != null) {
			mListener.scrollOritention(l, t, oldl, oldt);
		}
	}

	public void setScrollListener(ScrollListener l) {
		this.mListener = l;
	}

}

3D图片滑动倾斜放大倒影(大神连接

//主要代码
public boolean createReflectedImages() {
		// The gap we want between the reflection and the original image
		final int reflectionGap = 4;

		int index = 0;
		for (int imageId : mImageIds) {
			Bitmap originalImage = BitmapFactory.decodeResource(
					mContext.getResources(), imageId);
			int width = originalImage.getWidth();
			int height = originalImage.getHeight();
			// This will not scale but will flip on the Y axis
			Matrix matrix = new Matrix();
			matrix.preScale(1, -1);

			// Create a Bitmap with the flip matrix applied to it.
			// We only want the bottom half of the image
			Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0,
					height / 2, width, height / 2, matrix, false);

			// Create a new bitmap with same width but taller to fit
			// reflection
			Bitmap bitmapWithReflection = Bitmap.createBitmap(width,
					(height + height / 2), Config.ARGB_8888);

			// Create a new Canvas with the bitmap that's big enough for
			// the image plus gap plus reflection
			Canvas canvas = new Canvas(bitmapWithReflection);
			// Draw in the original image
			canvas.drawBitmap(originalImage, 0, 0, null);
			// Draw in the gap
			Paint deafaultPaint = new Paint();
			canvas.drawRect(0, height, width, height + reflectionGap,
					deafaultPaint);
			// Draw in the reflection
			canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);

			// Create a shader that is a linear gradient that covers the
			// reflection
			Paint paint = new Paint();
			LinearGradient shader = new LinearGradient(0,
					originalImage.getHeight(), 0,
					bitmapWithReflection.getHeight() + reflectionGap,
					0x70ffffff, 0x00ffffff, TileMode.CLAMP);
			// Set the paint to use this shader (linear gradient)
			paint.setShader(shader);
			// Set the Transfer mode to be porter duff and destination in
			paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
			// Draw a rectangle using the paint with our linear gradient
			canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()
					+ reflectionGap, paint);

			BitmapDrawable bd = new BitmapDrawable(bitmapWithReflection);
			bd.setAntiAlias(true);

			ImageView imageView = new ImageView(mContext);
			// imageView.setImageBitmap(bitmapWithReflection);
			imageView.setImageDrawable(bd);
			imageView.setLayoutParams(new GalleryFlow.LayoutParams(280, 460));
			imageView.setPadding(0, 40, 0, 0);
			// imageView.setScaleType(ScaleType.MATRIX);
			mImages[index++] = imageView;

		}
		return true;
	}

自由拖拽图标(龙旋

package com.minghui.easyapp.dragview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ImageView;

/**
 * 随意拖动的view
 */

@SuppressLint("AppCompatCustomView")
public class DragView extends ImageView {

	private int width;
	private int height;
	private int screenWidth;
	private int screenHeight;
	private Context context;

	// 是否拖动
	private boolean isDrag = false;

	public boolean isDrag() {
		return isDrag;
	}

	public DragView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context = context;
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		width = getMeasuredWidth();
		height = getMeasuredHeight();
		screenWidth = ScreenUtil.getScreenWidth(context);
		screenHeight = ScreenUtil.getScreenHeight(context)
				- getStatusBarHeight();

	}

	public int getStatusBarHeight() {
		int resourceId = getResources().getIdentifier("status_bar_height",
				"dimen", "android");
		return getResources().getDimensionPixelSize(resourceId);
	}

	private float downX;
	private float downY;

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		super.onTouchEvent(event);
		if (this.isEnabled()) {
			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				isDrag = false;
				downX = event.getX();
				downY = event.getY();
				break;
			case MotionEvent.ACTION_MOVE:
				Log.e("kid", "ACTION_MOVE");
				final float xDistance = event.getX() - downX;
				final float yDistance = event.getY() - downY;
				int l,
				r,
				t,
				b;
				// 当水平或者垂直滑动距离大于10,才算拖动事件
				if (Math.abs(xDistance) > 10 || Math.abs(yDistance) > 10) {
					Log.e("kid", "Drag");
					isDrag = true;
					l = (int) (getLeft() + xDistance);
					r = l + width;
					t = (int) (getTop() + yDistance);
					b = t + height;
					// 不划出边界判断,此处应按照项目实际情况,因为本项目需求移动的位置是手机全屏,
					// 所以才能这么写,如果是固定区域,要得到父控件的宽高位置后再做处理
					if (l < 0) {
						l = 0;
						r = l + width;
					} else if (r > screenWidth) {
						r = screenWidth;
						l = r - width;
					}
					if (t < 0) {
						t = 0;
						b = t + height;
					} else if (b > screenHeight) {
						b = screenHeight;
						t = b - height;
					}

					this.layout(l, t, r, b);
				}
				break;
			case MotionEvent.ACTION_UP:
				setPressed(false);
				break;
			case MotionEvent.ACTION_CANCEL:
				setPressed(false);
				break;
			}
			return true;
		}
		return false;
	}

}

形动画菜单(洒家卖蘑菇

package com.minghui.easyapp.utils;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.view.View;
import android.view.animation.BounceInterpolator;

public class NvaAnimator {
	/**
	 * 打开菜单 view:动画控件 index:第几个控件 num:有几个控件 radius:扇形半径
	 */
	public static void openAnim(View view, int index, int num, int radius,
			boolean isRadians) {
		if (view.getVisibility() != View.VISIBLE) {
			view.setVisibility(View.VISIBLE);
		}
		final int translationX;
		final int translationY;
		if (isRadians) {
			double angle = Math.toRadians(180) / (num - 1) * index;
			translationX = -(int) (radius * Math.cos(angle));
			translationY = -(int) (radius * Math.sin(angle));
		} else {
			translationX = index * 80 + 20 * index;
			translationY = 0;
		}
		ObjectAnimator one = ObjectAnimator.ofFloat(view, "translationX", 0,
				translationX);
		ObjectAnimator two = ObjectAnimator.ofFloat(view, "translationY", 0,
				translationY);
		ObjectAnimator three = ObjectAnimator.ofFloat(view, "rotation", 0, 360);
		ObjectAnimator four = ObjectAnimator.ofFloat(view, "scaleX", 0f, 1f);
		ObjectAnimator five = ObjectAnimator.ofFloat(view, "scaleY", 0f, 1f);
		ObjectAnimator six = ObjectAnimator.ofFloat(view, "alpha", 0f, 1);
		AnimatorSet set = new AnimatorSet();
		if (isRadians) {
			set.playTogether(one, two, three, four, five, six);
		} else {
			set.playTogether(one, two, six);
		}
		set.setDuration(2000);
		// 回弹效果
		set.setInterpolator(new BounceInterpolator());
		set.start();
	}

	/**
	 * 关闭扇形菜单
	 * 
	 * @param view
	 * @param index
	 * @param num
	 * @param radius
	 */
	public static void closeAnim(View view, int index, int num, int radius,
			boolean isRadians) {
		if (view.getVisibility() != View.VISIBLE) {
			view.setVisibility(View.VISIBLE);
		}
		final int translationX;
		final int translationY;
		if (isRadians) {
			double angle = Math.toRadians(180) / (num - 1) * index;
			translationX = -(int) (radius * Math.cos(angle));
			translationY = -(int) (radius * Math.sin(angle));
		} else {
			translationX = index * 80 + 20 * index;
			translationY = 0;
		}
		ObjectAnimator one = ObjectAnimator.ofFloat(view, "translationX",
				translationX, 0);
		ObjectAnimator two = ObjectAnimator.ofFloat(view, "translationY",
				translationY, 0);
		ObjectAnimator three = ObjectAnimator.ofFloat(view, "rotation", 0, 360);
		ObjectAnimator four = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0f);
		ObjectAnimator five = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0f);
		ObjectAnimator six = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f);

		AnimatorSet set = new AnimatorSet();
		if (isRadians) {
			set.playTogether(one, two, three, four, five, six);
		} else {
			set.playTogether(one, two, six);
		}
		set.setDuration(2000);
		// 回弹效果
		set.setInterpolator(new BounceInterpolator());
		set.start();
	}
}

纠正摄像头渲染方向(郑海波

    //判断是否有前摄像头    
    @TargetApi(9)
	private int FindFrontCamera() {
		int cameraCount = 0;
		Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
		cameraCount = Camera.getNumberOfCameras(); // get cameras number

		for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
			Camera.getCameraInfo(camIdx, cameraInfo); // get camerainfo
			if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { // ��������ͷ�ķ�λ��Ŀǰ�ж���ֵ�����ֱ�ΪCAMERA_FACING_FRONTǰ�ú�CAMERA_FACING_BACK����
				return camIdx;
			}
		}
		return -1;
	}
    //判断是否有后摄像头
	@TargetApi(9)
	private int FindBackCamera() {
		int cameraCount = 0;
		Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
		cameraCount = Camera.getNumberOfCameras(); // get cameras number

		for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
			Camera.getCameraInfo(camIdx, cameraInfo); // get camerainfo
			if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { // ��������ͷ�ķ�λ��Ŀǰ�ж���ֵ�����ֱ�ΪCAMERA_FACING_FRONTǰ�ú�CAMERA_FACING_BACK����
				return camIdx;
			}
		}
		return -1;
	}

    /**
	 * 根据横竖屏自动调节preview方向,Starting from API level 14, this method can be called
	 * when preview is active.
	 * 
	 * @param activity
	 * @param cameraId
	 * @param camera
	 */
	public static void setCameraDisplayOrientation(Activity activity,
			int cameraId, Camera camera) {
		Camera.CameraInfo info = new Camera.CameraInfo();
		Camera.getCameraInfo(cameraId, info);
		int rotation = activity.getWindowManager().getDefaultDisplay()
				.getRotation();

		// degrees the angle that the picture will be rotated clockwise. Valid
		// values are 0, 90, 180, and 270.
		// The starting position is 0 (landscape).
		int degrees = 0;
		switch (rotation) {
		case Surface.ROTATION_0:
			degrees = 0;
			break;
		case Surface.ROTATION_90:
			degrees = 90;
			break;
		case Surface.ROTATION_180:
			degrees = 180;
			break;
		case Surface.ROTATION_270:
			degrees = 270;
			break;
		}
		int result;
		if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
			result = (info.orientation + degrees) % 360;
			result = (360 - result) % 360; // compensate the mirror
		} else {
			// back-facing
			result = (info.orientation - degrees + 360) % 360;
		}
		camera.setDisplayOrientation(result);
	}

20181219第二版demo---添加了扇形动画菜单+自由拖拽图标+3D图片滑动倾斜放大倒影+自定义scrollview实现滑动监听等。

这里是项目更新demohttps://github.com/Life1412378121/EasyLive

THE END 感谢您的查看,如喜欢,欢迎您的star/fork ,小菜我叫吴明辉,期待与您一同打造一个无广告甚至免费的万能播放器。
 

猜你喜欢

转载自blog.csdn.net/qq_35350654/article/details/85101458