100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Android实现仿网易云音乐黑胶唱片效果

Android实现仿网易云音乐黑胶唱片效果

时间:2022-08-15 17:01:05

相关推荐

Android实现仿网易云音乐黑胶唱片效果

Android实现仿网易云音乐黑胶唱片效果

前言:

网易云音乐的黑胶唱片效果一直是很多音乐迷的最爱,之前实现过此效果,今天总结一下,直接上代码:

1.自定义圆形ImageView:

package com.example.vinylrecordplayer.viewimport android.annotation.SuppressLintimport android.content.Contextimport android.graphics.*import android.util.AttributeSetimport androidx.appcompat.widget.AppCompatImageViewimport com.example.vinylrecordplayer.R/*** @author: njb* @date: /5/21 22:56* @desc:*/@Suppress("NAME_SHADOWING")class RoundImageView : AppCompatImageView {private val paint: Paint by lazy {Paint() }private var roundWidth = 10private var roundHeight = 10private val paint2: Paint by lazy {Paint() }constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context,attrs,defStyle) {init(context, attrs)}constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {init(context, attrs)}constructor(context: Context) : super(context) {init(context, null)}@SuppressLint("Recycle")private fun init(context: Context, attrs: AttributeSet?) {if (attrs != null) {val attrs = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView)roundWidth = attrs.getDimensionPixelSize(R.styleable.RoundImageView_x_radius, roundWidth)roundHeight = attrs.getDimensionPixelSize(R.styleable.RoundImageView_y_radius, roundHeight)} else {val density = context.resources.displayMetrics.densityroundWidth = (roundWidth * density).toInt()roundHeight = (roundHeight * density).toInt()}paint.color = Color.WHITEpaint.isAntiAlias = truepaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)}override fun draw(canvas: Canvas) {val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)val canvas2 = Canvas(bitmap)super.draw(canvas2)drawLiftUp(canvas2)drawLiftDown(canvas2)drawRightUp(canvas2)drawRightDown(canvas2)canvas.drawBitmap(bitmap, 0f, 0f, paint2)bitmap.recycle()}private fun drawLiftUp(canvas: Canvas) {val path = Path()path.moveTo(0f, roundHeight.toFloat())path.lineTo(0f, 0f)path.lineTo(roundWidth.toFloat(), 0f)path.arcTo(RectF(0f, 0f, (roundWidth * 2).toFloat(), (roundHeight * 2).toFloat()),-90f,-90f)path.close()canvas.drawPath(path, paint)}private fun drawLiftDown(canvas: Canvas) {val path = Path()path.moveTo(0f, (height - roundHeight).toFloat())path.lineTo(0f, height.toFloat())path.lineTo(roundWidth.toFloat(), height.toFloat())path.arcTo(RectF(0f,(height - roundHeight * 2).toFloat(),(roundWidth * 2).toFloat(),height.toFloat()), 90f, 90f)path.close()canvas.drawPath(path, paint)}private fun drawRightDown(canvas: Canvas) {val path = Path()path.moveTo((width - roundWidth).toFloat(), height.toFloat())path.lineTo(width.toFloat(), height.toFloat())path.lineTo(width.toFloat(), (height - roundHeight).toFloat())path.arcTo(RectF((width - roundWidth * 2).toFloat(),(height - roundHeight * 2).toFloat(),width.toFloat(),height.toFloat()), -0f, 90f)path.close()canvas.drawPath(path, paint)}private fun drawRightUp(canvas: Canvas) {val path = Path()path.moveTo(width.toFloat(), roundHeight.toFloat())path.lineTo(width.toFloat(), 0f)path.lineTo((width - roundWidth).toFloat(), 0f)path.arcTo(RectF((width - roundWidth * 2).toFloat(),0f,width.toFloat(),(roundHeight * 2).toFloat()), -90f, 90f)path.close()canvas.drawPath(path, paint)}}

2.自定义悬浮窗按钮:

package com.example.vinylrecordplayer.viewimport android.content.Contextimport android.util.AttributeSetimport android.view.Gravityimport android.view.MotionEventimport android.view.Viewimport android.widget.LinearLayoutimport com.example.vinylrecordplayer.Rimport com.example.vinylrecordplayer.utils.DisplayUtilsimport com.example.vinylrecordplayer.utils.DisplayUtils.dip2pximport kotlinx.android.synthetic.main.play_music_rotate.view.*import kotlin.math.abs/*** des 自定义音乐悬浮按钮* @date /6/28* @author njb*/class FloatPlayLayout : LinearLayout {/*** content应该展示的宽度*/private val contentWidth = dip2px(context, 180f)constructor(context: Context) : super(context) {initView(context)}constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {initView(context)}constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context,attrs,defStyleAttr) {initView(context)}override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {when (ev.action) {MotionEvent.ACTION_DOWN -> {moveY = ev.y}MotionEvent.ACTION_MOVE -> {//兼容某些机型一碰就触发滑动if (abs(ev.y - moveY) > 100) {return true}}}return false}private var moveY = 0foverride fun onTouchEvent(event: MotionEvent): Boolean {when (event.action) {MotionEvent.ACTION_MOVE -> {var offsetY = translationY + (event.y - moveY)//因为translationY不管处于ViewGroup什么位置,初始值都为0,所以要买个top//最小值if (offsetY < -top + dip2px(context, 100f)) {offsetY = -top.toFloat() + dip2px(context, 100f)}//最大值if (offsetY > DisplayUtils.getScreenHeight(context) - top - dip2px(context, 150f)) {offsetY = DisplayUtils.getScreenHeight(context) - top.toFloat() - dip2px(context,150f)}translationY = offsetYreturn true}}return super.onInterceptTouchEvent(event)}private fun initView(context: Context) {View.inflate(context, R.layout.play_music_rotate, this)//居中显示gravity = Gravity.CENTER//设置阴影click()}/*** 事件*/private fun click() {}/*** 悬浮窗点击事件*/fun rootClick(onClick: (View) -> Unit) {anchorLiveMusic.clickNoRepeat {onClick.invoke(it)}}}/*** 防止重复点击* @param interval 重复间隔* @param onClick 事件响应*/var lastTime = 0Lfun View.clickNoRepeat(interval: Long = 400, onClick: (View) -> Unit) {setOnClickListener {val currentTime = System.currentTimeMillis()if (lastTime != 0L && (currentTime - lastTime < interval)) {return@setOnClickListener}lastTime = currentTimeonClick(it)}}

3.自定义旋转的唱片view:

package com.example.vinylrecordplayer.view;import android.animation.ObjectAnimator;import android.animation.ValueAnimator;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.view.animation.LinearInterpolator;import android.widget.FrameLayout;import android.widget.ImageView;import androidx.annotation.NonNull;import androidx.annotation.Nullable;import com.example.vinylrecordplayer.R;/*** @author: njb* @date: /5/25 16:34* @desc: 描述*/public class RotateAlbumView extends FrameLayout {private static final String TAG = "RotateAlbumView";private ImageView ivAlbumPic;private ObjectAnimator animator;public RotateAlbumView(@NonNull Context context) {this(context, null);}public RotateAlbumView(@NonNull Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public RotateAlbumView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context);}// 设置旋转动画(属性动画)private void init(Context context) {View.inflate(context, R.layout.view_rotate_album, this);ivAlbumPic = (ImageView) findViewById(R.id.view_pic);animator = ObjectAnimator.ofFloat(ivAlbumPic, "rotation", 0.0F, 360.0F);animator.setDuration(5 * 1000);animator.setInterpolator(new LinearInterpolator());animator.setRepeatCount(ObjectAnimator.INFINITE);animator.setRepeatMode(ValueAnimator.RESTART);setPlaying(true);}// 更新播放状态public void setPlaying(boolean isPlaying) {Log.d(TAG, "update RotateAlbumView: isPlaying = " + isPlaying);if (isPlaying) {if (!animator.isRunning()) {animator.start();} else {animator.resume();}} else {if (!animator.isStarted() || !animator.isRunning()) {animator.cancel();}animator.pause();}}@Overridepublic boolean onTouchEvent(MotionEvent event) {return super.onTouchEvent(event);}@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();Log.d(TAG, "RotateAlbumView: onDetachedFromWindow");animator.cancel();}}

4.自定义黑胶效果:

package com.example.vinylrecordplayer.view;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.SweepGradient;import android.util.AttributeSet;import android.view.View;import androidx.annotation.ColorInt;import androidx.annotation.ColorRes;import androidx.annotation.Nullable;import com.example.vinylrecordplayer.R;/*** @author: njb* @date: /5/25 16:35* @desc: 描述*/public class VinylRecordView extends View {private Paint paint;// 圆环半径private int ringWidth;// 渐变色private int[] colors;private SweepGradient gradient;// 圆线距圆环内边的距离private int[] ringLinesMarginOut = {dp2px(3.78F),dp2px(7.03F),dp2px(10.27F),dp2px(12.97F)};// 圆线高度private int ringLineWidth;public VinylRecordView(Context context) {this(context, null);}public VinylRecordView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public VinylRecordView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context, attrs);}private void init(Context context, AttributeSet attrs) {paint = new Paint();paint.setAntiAlias(true);paint.setStyle(Paint.Style.STROKE);paint.setStrokeCap(Paint.Cap.ROUND);colors = new int[]{getColor(R.color.widget_album_ring_color1), getColor(R.color.widget_album_ring_color2),getColor(R.color.widget_album_ring_color1), getColor(R.color.widget_album_ring_color2),getColor(R.color.widget_album_ring_color1)};TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VinylRecordView);ringWidth = (int) typedArray.getDimension(R.styleable.VinylRecordView_ring_width, getResources().getDimension(R.dimen.widget_album_ring_width));ringLineWidth = (int) typedArray.getDimension(R.styleable.VinylRecordView_ring_line_width, getResources().getDimension(R.dimen.widget_album_ring_line_width));typedArray.recycle();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);paint.setStrokeWidth(ringWidth);paint.setColor(getColor(R.color.widget_album_ring_color1));if (gradient == null) {gradient = new SweepGradient(getWidth() * 0.5F, getHeight() * 0.5F, colors, new float[]{0F, 0.25F, 0.5F, 0.75F, 1F});}paint.setShader(gradient);canvas.drawCircle(getWidth() * 0.5F, getHeight() * 0.5F, (getWidth() - ringWidth) * 0.5F, paint);paint.setShader(null);paint.setStrokeWidth(ringLineWidth);paint.setColor(getColor(R.color.widget_album_ring_line_color));for (int marginOut : ringLinesMarginOut) {canvas.drawCircle(getWidth() * 0.5F, getHeight() * 0.5F, getWidth() * 0.5F - marginOut - ringLineWidth * 0.5F, paint);}}private int dp2px(float dp) {float scale = getResources().getDisplayMetrics().density;return (int) (dp * scale + 0.5F);}@ColorIntprivate int getColor(@ColorRes int colorId) {return getResources().getColor(colorId, null);}}

5.MainActivity使用:

package com.example.vinylrecordplayerimport android.os.Bundleimport android.widget.Toastimport androidx.appcompat.app.AppCompatActivityimport kotlinx.android.synthetic.main.activity_main.*class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)initView()}private fun initView() {floatMusic.rootClick {Toast.makeText(this@MainActivity,"点击了悬浮窗",Toast.LENGTH_SHORT).show()}}}

6.主界面代码:

<?xml version="1.0" encoding="utf-8"?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><com.example.vinylrecordplayer.view.FloatPlayLayoutandroid:id="@+id/floatMusic"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintRight_toRightOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>

7.实现效果如下:

8.源码地址:

/jackning_admin/vinyl-record-demo

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。