当前位置: 首页 > news >正文

临朐网站制作哪家好semantic scholar

临朐网站制作哪家好,semantic scholar,东莞市公租房申请网站-建设网,网站支付界面怎么做原文:TV Metro界面(仿泰捷视频TV版)源码解析版权声明:我已委托“维权骑士”(rightknights.com)为我的文章进行维权行动.转载务必转载所有,且须注明出处。否则保留追究法律责任 https://blog.csdn.net/hejju…
原文:TV Metro界面(仿泰捷视频TV版)源码解析

版权声明:我已委托“维权骑士”(rightknights.com)为我的文章进行维权行动.转载务必转载所有,且须注明出处。否则保留追究法律责任 https://blog.csdn.net/hejjunlin/article/details/52822499

转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52822499

前言:上一篇介绍了仿泰捷视频TV版的效果,对应github:https://github.com/hejunlin2013/TVSample,今天就介绍下对应的源码部分

先看下View的层级结构图:

这里写图片描述

在SmoothHorizonalScrollView(继承HorizonalScrollView)下挂上DrawingOrderRelativeLayout(继承自RelativeLayout),接下来就是一个个的MetroItem,每个Item下包含ImageView(海报图),CornerView(VIP角标),TextView(海报图简介),像第一张和第二张,以及最后两张,显示是频道入口,只有一个ImageView,无CornerView及TextView。

角标View

public class CornerVew extends View {private String mTextContent;//显示字体内容private int mTextColor;//字体颜色private float mTextSize;//字体大小private boolean mTextBold;//是否字体加粗private boolean mFillTriangle;//是否三角形private boolean mTextAllCaps;//private int mBackgroundColor;//背景颜色private float mMinSize;//最小值private float mPadding;//padding值private int mGravity;//private static final int DEFAULT_DEGREES = 45;//切角private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿private Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);private Path mPath = new Path();public CornerVew(Context context) {this(context, null);}public CornerVew(Context context, AttributeSet attrs) {super(context, attrs);obtainAttributes(context, attrs);mTextPaint.setTextAlign(Paint.Align.CENTER);//从中间开始画}private void obtainAttributes(Context context, AttributeSet attrs) {TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CornerVew);mTextContent = ta.getString(R.styleable.CornerVew_cv_text);mTextColor = ta.getColor(R.styleable.CornerVew_cv_text_color, Color.parseColor("#ffffff"));mTextSize = ta.getDimension(R.styleable.CornerVew_cv_text_size, sp2px(11));mTextBold = ta.getBoolean(R.styleable.CornerVew_cv_text_bold, true);//加粗mTextAllCaps = ta.getBoolean(R.styleable.CornerVew_cv_text_all_caps, true);mFillTriangle = ta.getBoolean(R.styleable.CornerVew_cv_fill_triangle, false);mBackgroundColor = ta.getColor(R.styleable.CornerVew_cv_background_color, Color.parseColor("#FF4081"));mMinSize = ta.getDimension(R.styleable.CornerVew_cv_min_size, mFillTriangle ? dp2px(35) : dp2px(50));mPadding = ta.getDimension(R.styleable.CornerVew_cv_padding, dp2px(3.5f));mGravity = ta.getInt(R.styleable.CornerVew_cv_gravity, Gravity.TOP | Gravity.LEFT);ta.recycle();}@Overrideprotected void onDraw(Canvas canvas) {int size = getHeight();mTextPaint.setColor(mTextColor);mTextPaint.setTextSize(mTextSize);mTextPaint.setFakeBoldText(mTextBold);mBackgroundPaint.setColor(mBackgroundColor);float textHeight = mTextPaint.descent() - mTextPaint.ascent();if (mFillTriangle) {if (mGravity == (Gravity.TOP | Gravity.LEFT)) {//左上角mPath.reset();mPath.moveTo(0, 0);mPath.lineTo(0, size);mPath.lineTo(size, 0);mPath.close();canvas.drawPath(mPath, mBackgroundPaint);drawTextWhenFill(size, -DEFAULT_DEGREES, canvas, true);} else if (mGravity == (Gravity.TOP | Gravity.RIGHT)) {//右上角mPath.reset();mPath.moveTo(size, 0);mPath.lineTo(0, 0);mPath.lineTo(size, size);mPath.close();canvas.drawPath(mPath, mBackgroundPaint);drawTextWhenFill(size, DEFAULT_DEGREES, canvas, true);} else if (mGravity == (Gravity.BOTTOM | Gravity.LEFT)) {//左下角mPath.reset();mPath.moveTo(0, size);mPath.lineTo(0, 0);mPath.lineTo(size, size);mPath.close();canvas.drawPath(mPath, mBackgroundPaint);drawTextWhenFill(size, DEFAULT_DEGREES, canvas, false);} else if (mGravity == (Gravity.BOTTOM | Gravity.RIGHT)) {//右下角mPath.reset();mPath.moveTo(size, size);mPath.lineTo(0, size);mPath.lineTo(size, 0);mPath.close();canvas.drawPath(mPath, mBackgroundPaint);drawTextWhenFill(size, -DEFAULT_DEGREES, canvas, false);}} else {double delta = (textHeight + mPadding * 2) * Math.sqrt(2);if (mGravity == (Gravity.TOP | Gravity.LEFT)) {mPath.reset();mPath.moveTo(0, (float) (size - delta));mPath.lineTo(0, size);mPath.lineTo(size, 0);mPath.lineTo((float) (size - delta), 0);mPath.close();canvas.drawPath(mPath, mBackgroundPaint);drawText(size, -DEFAULT_DEGREES, canvas, textHeight, true);} else if (mGravity == (Gravity.TOP | Gravity.RIGHT)) {mPath.reset();mPath.moveTo(0, 0);mPath.lineTo((float) delta, 0);mPath.lineTo(size, (float) (size - delta));mPath.lineTo(size, size);mPath.close();canvas.drawPath(mPath, mBackgroundPaint);drawText(size, DEFAULT_DEGREES, canvas, textHeight, true);} else if (mGravity == (Gravity.BOTTOM | Gravity.LEFT)) {mPath.reset();mPath.moveTo(0, 0);mPath.lineTo(0, (float) delta);mPath.lineTo((float) (size - delta), size);mPath.lineTo(size, size);mPath.close();canvas.drawPath(mPath, mBackgroundPaint);drawText(size, DEFAULT_DEGREES, canvas, textHeight, false);} else if (mGravity == (Gravity.BOTTOM | Gravity.RIGHT)) {mPath.reset();mPath.moveTo(0, size);mPath.lineTo((float) delta, size);mPath.lineTo(size, (float) delta);mPath.lineTo(size, 0);mPath.close();canvas.drawPath(mPath, mBackgroundPaint);drawText(size, -DEFAULT_DEGREES, canvas, textHeight, false);}}}private void drawText(int size, float degrees, Canvas canvas, float textHeight, boolean isTop) {canvas.save();canvas.rotate(degrees, size / 2f, size / 2f);float delta = isTop ? -(textHeight + mPadding * 2) / 2 : (textHeight + mPadding * 2) / 2;float textBaseY = size / 2 - (mTextPaint.descent() + mTextPaint.ascent()) / 2 + delta;canvas.drawText(mTextAllCaps ? mTextContent.toUpperCase() : mTextContent,getPaddingLeft() + (size - getPaddingLeft() - getPaddingRight()) / 2, textBaseY, mTextPaint);canvas.restore();}private void drawTextWhenFill(int size, float degrees, Canvas canvas, boolean isTop) {canvas.save();canvas.rotate(degrees, size / 2f, size / 2f);float delta = isTop ? -size / 4 : size / 4;float textBaseY = size / 2 - (mTextPaint.descent() + mTextPaint.ascent()) / 2 + delta;canvas.drawText(mTextAllCaps ? mTextContent.toUpperCase() : mTextContent,getPaddingLeft() + (size - getPaddingLeft() - getPaddingRight()) / 2, textBaseY, mTextPaint);canvas.restore();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int measuredWidth = measureWidth(widthMeasureSpec);setMeasuredDimension(measuredWidth, measuredWidth);}private int measureWidth(int widthMeasureSpec) {int result;int specMode = MeasureSpec.getMode(widthMeasureSpec);//获取测量模式int specSize = MeasureSpec.getSize(widthMeasureSpec);//获取测量大小if (specMode == MeasureSpec.EXACTLY) {//精确模式result = specSize;} else {int padding = getPaddingLeft() + getPaddingRight();mTextPaint.setColor(mTextColor);mTextPaint.setTextSize(mTextSize);float textWidth = mTextPaint.measureText(mTextContent + "");result = (int) ((padding + (int) textWidth) * Math.sqrt(2));if (specMode == MeasureSpec.AT_MOST) {result = Math.min(result, specSize);}result = Math.max((int) mMinSize, result);}return result;}protected int dp2px(float dp) {final float scale = getResources().getDisplayMetrics().density;return (int) (dp * scale + 0.5f);}protected int sp2px(float sp) {final float scale = getResources().getDisplayMetrics().scaledDensity;return (int) (sp * scale + 0.5f);}
}

绘制子视图顺序的Layout

public class DrawingOrderRelativeLayout extends RelativeLayout {private int position = 0;public DrawingOrderRelativeLayout(Context context) {super(context);}public DrawingOrderRelativeLayout(Context context, AttributeSet attrs) {super(context, attrs);this.setChildrenDrawingOrderEnabled(true);}public void setCurrentPosition(int pos) {this.position = pos;}@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {View focused = findFocus();//找到焦点int pos = indexOfChild(focused);if (pos >= 0 && pos < getChildCount()) {setCurrentPosition(pos);postInvalidate();}return super.dispatchKeyEvent(event);}@Overrideprotected int getChildDrawingOrder(int childCount, int i) {//改变ViewGroup的子视图绘制顺序View v = getFocusedChild();int pos = indexOfChild(v);if (pos >= 0 && pos < childCount)setCurrentPosition(pos);if (i == childCount - 1) {//从最后一个view开始绘制return position;}if (i == position) {return childCount - 1;}return i;}}

MetroItem


public class MetroItemFrameLayout extends FrameLayout implements IMetroItemRound {private MetroItemRound mMetroItemRound;public MetroItemFrameLayout(Context context) {super(context);init(context, null, 0);}public MetroItemFrameLayout(Context context, AttributeSet attrs) {super(context, attrs);init(context, attrs, 0);}public MetroItemFrameLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init(context, attrs, defStyle);}private void init(Context context, AttributeSet attrs, int defStyle) {mMetroItemRound = new MetroItemRound(this, context, attrs, defStyle);setWillNotDraw(false);//设置为false时,就会调用自定义的布局}@Overridepublic void draw(Canvas canvas) {mMetroItemRound.draw(canvas);}@Overridepublic MetroItemRound getRoundImpl() {return mMetroItemRound;}@Overridepublic void drawRadious(Canvas canvas) {super.draw(canvas);}
}

MetroItem的圆角

public class MetroItemRound {private float mRadius;//圆角private float mTopLeftRadius;//左上角的圆角private float mTopRightRadius;//右上角的圆角private float mBottomLeftRadius;//左下角的圆角private float mBottomRightRadius;//右下角的圆角private Paint mPaint;//画笔private Path mPath;//画布private IMetroItemRound mView;public MetroItemRound(IMetroItemRound view, Context context, AttributeSet attrs, int defStyle) {init(context, attrs, defStyle);mView = view;}private void init(Context context, AttributeSet attrs, int defStyle) {mPaint = new Paint();//实例化画笔mPaint.setColor(Color.WHITE);//设置画笔颜色为白色mPaint.setAntiAlias(true);//设置抗锯齿mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));//取下层绘制非交集部分mPath = new Path();//设置路径TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MetroItemRound, defStyle, 0);mBottomLeftRadius = a.getDimension(R.styleable.MetroItemRound_bottomLeftRadius, -1);mBottomRightRadius = a.getDimension(R.styleable.MetroItemRound_bottomRightRadius, -1);mTopLeftRadius = a.getDimension(R.styleable.MetroItemRound_topLeftRadius, -1);mTopRightRadius = a.getDimension(R.styleable.MetroItemRound_topRightRadius, -1);mRadius = a.getDimension(R.styleable.MetroItemRound_radius, -1);if (mRadius > 0) {if (mBottomLeftRadius < 0)mBottomLeftRadius = mRadius;if (mBottomRightRadius < 0)mBottomRightRadius = mRadius;if (mTopLeftRadius < 0)mTopLeftRadius = mRadius;if (mTopRightRadius < 0)mTopRightRadius = mRadius;}a.recycle();}public void draw(Canvas canvas) {if (mBottomLeftRadius <= 0 && mBottomRightRadius <= 0 && mTopRightRadius <= 0 && mTopLeftRadius <= 0) {mView.drawRadious(canvas);return;}int width = mView.getWidth();int height = mView.getHeight();int count = canvas.save();int count2 = canvas.saveLayer(0, 0, width, height, null, Canvas.ALL_SAVE_FLAG);addRoundPath(width, height);mView.drawRadious(canvas);//画一个圆角canvas.drawPath(mPath, mPaint);canvas.restoreToCount(count2);canvas.restoreToCount(count);}private void addRoundPath(int width, int height) {//topleft pathif (mTopLeftRadius > 0) {Path topLeftPath = new Path();topLeftPath.moveTo(0, mTopLeftRadius);//移动画笔到最左边x为0,y为mTopLeftRadiustopLeftPath.lineTo(0, 0);//绘制直线,从坐标0,0开始topLeftPath.lineTo(mTopLeftRadius, 0);//RectF arc = new RectF(0, 0, mTopLeftRadius * 2, mTopLeftRadius * 2);//矩形区域//和Rect的区别是RectF表示精确到浮点型topLeftPath.arcTo(arc, -90, -90);//画弧线的路径,从-90到-90,逆时针画topLeftPath.close();//mPath.addPath(topLeftPath);}//topRight pathif (mTopRightRadius > 0) {Path topRightPath = new Path();topRightPath.moveTo(width, mTopRightRadius);//移动画笔到最右边x为width,y为mTopRightRadiustopRightPath.lineTo(width, 0);topRightPath.lineTo(width - mTopRightRadius, 0);RectF arc = new RectF(width - mTopRightRadius * 2, 0, width, mTopRightRadius * 2);topRightPath.arcTo(arc, -90, 90);//这里是画180的椭圆topRightPath.close();mPath.addPath(topRightPath);}//bottomLeft pathif (mBottomLeftRadius > 0) {Path bottomLeftPath = new Path();bottomLeftPath.moveTo(0, height - mBottomLeftRadius);bottomLeftPath.lineTo(0, height);bottomLeftPath.lineTo(mBottomLeftRadius, height);RectF arc = new RectF(0, height - mBottomLeftRadius * 2, mBottomLeftRadius * 2, height);bottomLeftPath.arcTo(arc, 90, 90);bottomLeftPath.close();mPath.addPath(bottomLeftPath);}//bottomRight pathif (mBottomRightRadius > 0) {Path bottomRightPath = new Path();bottomRightPath.moveTo(width - mBottomRightRadius, height);bottomRightPath.lineTo(width, height);bottomRightPath.lineTo(width, height - mBottomRightRadius);RectF arc = new RectF(width - mBottomRightRadius * 2, height - mBottomRightRadius * 2, width, height);bottomRightPath.arcTo(arc, 0, 90);bottomRightPath.close();mPath.addPath(bottomRightPath);}}
}

MetroItem中外边框处理类

public class MetroViewBorderHandler implements IMetroViewBorder {private String TAG = MetroViewBorderHandler.class.getSimpleName();protected boolean mScalable = true;//是否缩小protected float mScale = 1.1f;//设置放大比例protected long mDurationTraslate = 200;//焦点移动的动画时间protected int mMargin = 0;protected View lastFocus, oldLastFocus;//上一个焦点,新的位置的焦点protected AnimatorSet mAnimatorSet;//动画集合,可组合多个动画protected List<Animator> mAnimatorList = new ArrayList<Animator>();protected View mTarget;protected boolean mEnableTouch = true;public MetroViewBorderHandler() {mFocusListener.add(mFocusMoveListener);//设置焦点移动时监听mFocusListener.add(mFocusScaleListener);//设置焦点放大缩小监听mFocusListener.add(mFocusPlayListener);mFocusListener.add(mAbsListViewFocusListener);//用作listview,gridview相关}public interface FocusListener {void onFocusChanged(View oldFocus, View newFocus);}protected List<FocusListener> mFocusListener = new ArrayList<FocusListener>(1);protected List<Animator.AnimatorListener> mAnimatorListener = new ArrayList<Animator.AnimatorListener>(1);public FocusListener mFocusScaleListener = new FocusListener() {@Overridepublic void onFocusChanged(View oldFocus, View newFocus) {//焦点变化,设置新焦点移动的位置变成放大状态mAnimatorList.addAll(getScaleAnimator(newFocus, true));if (oldFocus != null) {//上一个view(之前是焦点态,onFocusChanged变成非焦点态)不为null,设置上一个为缩小状态mAnimatorList.addAll(getScaleAnimator(oldFocus, false));}}};public FocusListener mFocusPlayListener = new FocusListener() {@Overridepublic void onFocusChanged(View oldFocus, View newFocus) {try {if (newFocus instanceof AbsListView) {//如果新的view是AbsListView的实例,直接returnreturn;}AnimatorSet animatorSet = new AnimatorSet();animatorSet.setInterpolator(new DecelerateInterpolator(1));//设置插值器animatorSet.setDuration(mDurationTraslate);//设置动画时间animatorSet.playTogether(mAnimatorList);//表示两个动画同进执行for (Animator.AnimatorListener listener : mAnimatorListener) {animatorSet.addListener(listener);}mAnimatorSet = animatorSet;if (oldFocus == null) {//之前view为null,表示首次状态时animatorSet.setDuration(0);//无动画时长mTarget.setVisibility(View.VISIBLE);}animatorSet.start();//开启动画} catch (Exception ex) {ex.printStackTrace();}}};public FocusListener mFocusMoveListener = new FocusListener() {@Overridepublic void onFocusChanged(View oldFocus, View newFocus) {if (newFocus == null) return;//下一个view不存在时,直接returntry {mAnimatorList.addAll(getMoveAnimator(newFocus, 0, 0));//添加} catch (Exception ex) {ex.printStackTrace();}}};public FocusListener mAbsListViewFocusListener = new FocusListener() {@Overridepublic void onFocusChanged(View oldFocus, View newFocus) {try {if (oldFocus == null) {for (int i = 0; i < attacheViews.size(); i++) {View view = attacheViews.get(i);if (view instanceof AbsListView) {final AbsListView absListView = (AbsListView) view;mTarget.setVisibility(View.INVISIBLE);if (mFirstFocus) {absListView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {@Overridepublic void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {try {absListView.removeOnLayoutChangeListener(this);int factorX = 0, factorY = 0;Rect rect = new Rect();View firstView = (View) absListView.getSelectedView();firstView.getLocalVisibleRect(rect);if (Math.abs(rect.left - rect.right) > firstView.getMeasuredWidth()) {factorX = (Math.abs(rect.left - rect.right) - firstView.getMeasuredWidth()) / 2 - 1;factorY = (Math.abs(rect.top - rect.bottom) - firstView.getMeasuredHeight()) / 2;}List<Animator> animatorList = new ArrayList<Animator>(3);animatorList.addAll(getScaleAnimator(firstView, true));animatorList.addAll(getMoveAnimator(firstView, factorX, factorY));mTarget.setVisibility(View.VISIBLE);AnimatorSet animatorSet = new AnimatorSet();animatorSet.setDuration(0);animatorSet.playTogether(animatorList);animatorSet.start();} catch (Exception ex) {ex.printStackTrace();}}});}break;}}} else if (oldFocus instanceof AbsListView && newFocus instanceof AbsListView) {if (attacheViews.indexOf(oldFocus) >= 0 && attacheViews.indexOf(newFocus) >= 0) {AbsListView a = (AbsListView) oldFocus;AbsListView b = (AbsListView) newFocus;MyOnItemSelectedListener oldOn = (MyOnItemSelectedListener) onItemSelectedListenerList.get(oldFocus);MyOnItemSelectedListener newOn = (MyOnItemSelectedListener) onItemSelectedListenerList.get(newFocus);int factorX = 0, factorY = 0;Rect rect = new Rect();View firstView = (View) b.getSelectedView();firstView.getLocalVisibleRect(rect);if (Math.abs(rect.left - rect.right) > firstView.getMeasuredWidth()) {factorX = (Math.abs(rect.left - rect.right) - firstView.getMeasuredWidth()) / 2 - 1;factorY = (Math.abs(rect.top - rect.bottom) - firstView.getMeasuredHeight()) / 2;}List<Animator> animatorList = new ArrayList<Animator>(3);animatorList.addAll(getScaleAnimator(firstView, true));animatorList.addAll(getScaleAnimator(a.getSelectedView(), false));animatorList.addAll(getMoveAnimator(firstView, factorX, factorY));mTarget.setVisibility(View.VISIBLE);mAnimatorSet = new AnimatorSet();mAnimatorSet.setDuration(mDurationTraslate);mAnimatorSet.playTogether(animatorList);mAnimatorSet.start();oldOn.oldFocus = null;oldOn.newFocus = null;newOn.oldFocus = null;if (newOn.newFocus != null && newOn.oldFocus != null) {newOn.newFocus = null;} else {newOn.newFocus = b.getSelectedView();}}}} catch (Exception ex) {ex.printStackTrace();}}};protected List<Animator> getScaleAnimator(View view, boolean isScale) {List<Animator> animatorList = new ArrayList<Animator>(2);if (!mScalable) return animatorList;//如果没有放大,直接返回try {float scaleBefore = 1.0f;//放大前比例float scaleAfter = mScale;//放大后比例if (!isScale) {//scaleBefore = mScale;scaleAfter = 1.0f;}ObjectAnimator scaleX = new ObjectAnimator().ofFloat(view, "scaleX", scaleBefore, scaleAfter);ObjectAnimator scaleY = new ObjectAnimator().ofFloat(view, "scaleY", scaleBefore, scaleAfter);animatorList.add(scaleX);animatorList.add(scaleY);} catch (Exception ex) {ex.printStackTrace();}return animatorList;}protected List<Animator> getMoveAnimator(View newFocus, int factorX, int factorY) {List<Animator> animatorList = new ArrayList<Animator>();int newXY[];int oldXY[];try {newXY = getLocation(newFocus);//新的oldXY = getLocation(mTarget);int newWidth;int newHeight;int oldWidth = mTarget.getMeasuredWidth();int oldHeight = mTarget.getMeasuredHeight();if (mScalable) {float scaleWidth = newFocus.getMeasuredWidth() * mScale;float scaleHeight = newFocus.getMeasuredHeight() * mScale;newWidth = (int) (scaleWidth + mMargin * 2 + 0.5);newHeight = (int) (scaleHeight + mMargin * 2 + 0.5);newXY[0] = (int) (newXY[0] - (newWidth - newFocus.getMeasuredWidth()) / 2.0f) + factorX;newXY[1] = (int) (newXY[1] - (newHeight - newFocus.getMeasuredHeight()) / 2.0f + 0.5 + factorY);} else {newWidth = newFocus.getWidth();newHeight = newFocus.getHeight();}if (oldHeight == 0 && oldWidth == 0) {oldHeight = newHeight;oldWidth = newWidth;}PropertyValuesHolder valuesWithdHolder = PropertyValuesHolder.ofInt("width", oldWidth, newWidth);PropertyValuesHolder valuesHeightHolder = PropertyValuesHolder.ofInt("height", oldHeight, newHeight);PropertyValuesHolder valuesXHolder = PropertyValuesHolder.ofFloat("translationX", oldXY[0], newXY[0]);PropertyValuesHolder valuesYHolder = PropertyValuesHolder.ofFloat("translationY", oldXY[1], newXY[1]);final ObjectAnimator scaleAnimator = ObjectAnimator.ofPropertyValuesHolder(mTarget, valuesWithdHolder, valuesHeightHolder, valuesYHolder, valuesXHolder);scaleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic synchronized void onAnimationUpdate(ValueAnimator animation) {int width = (int) animation.getAnimatedValue("width");int height = (int) animation.getAnimatedValue("height");float translationX = (float) animation.getAnimatedValue("translationX");float translationY = (float) animation.getAnimatedValue("translationY");View view = (View) scaleAnimator.getTarget();assert view != null;int w = view.getLayoutParams().width;view.getLayoutParams().width = width;view.getLayoutParams().height = height;if (width > 0) {view.requestLayout();view.postInvalidate();}}});animatorList.add(scaleAnimator);} catch (Exception ex) {ex.printStackTrace();}return animatorList;}protected int[] getLocation(View view) {int[] location = new int[2];//location[0]代表x坐标,location [1] 代表y坐标。try {//获取在整个屏幕内的绝对坐标,注意这个值是要从屏幕顶端算起,也就是包括了通知栏的高度。view.getLocationOnScreen(location);} catch (Exception ex) {ex.printStackTrace();}return location;}public void addOnFocusChanged(FocusListener focusListener) {this.mFocusListener.add(focusListener);}public void removeOnFocusChanged(FocusListener focusListener) {this.mFocusListener.remove(focusListener);}public void addAnimatorListener(Animator.AnimatorListener animatorListener) {this.mAnimatorListener.add(animatorListener);}public void removeAnimatorListener(Animator.AnimatorListener animatorListener) {this.mAnimatorListener.remove(animatorListener);}private class VisibleScope {public boolean isVisible;public View oldFocus;public View newFocus;}protected VisibleScope checkVisibleScope(View oldFocus, View newFocus) {VisibleScope scope = new VisibleScope();try {scope.oldFocus = oldFocus;scope.newFocus = newFocus;scope.isVisible = true;if (attacheViews.indexOf(oldFocus) >= 0 && attacheViews.indexOf(newFocus) >= 0) {return scope;}if (oldFocus != null && newFocus != null) {if (oldFocus.getParent() != newFocus.getParent()) {if ((attacheViews.indexOf(newFocus.getParent()) < 0) || (attacheViews.indexOf(oldFocus.getParent()) < 0 && attacheViews.indexOf(newFocus.getParent()) > 0)) {mTarget.setVisibility(View.INVISIBLE);AnimatorSet animatorSet = new AnimatorSet();animatorSet.playTogether(getScaleAnimator(oldFocus, false));animatorSet.setDuration(0).start();scope.isVisible = false;return scope;} else {mTarget.setVisibility(View.VISIBLE);}if (attacheViews.indexOf(oldFocus.getParent()) < 0) {scope.oldFocus = null;}} else {if (attacheViews.indexOf(newFocus.getParent()) < 0) {mTarget.setVisibility(View.INVISIBLE);scope.isVisible = false;return scope;}}}mTarget.setVisibility(View.VISIBLE);} catch (Exception ex) {ex.printStackTrace();}return scope;}@Overridepublic void onFocusChanged(View target, View oldFocus, View newFocus) {try {Log.d(TAG, "onFocusChanged:" + oldFocus + "=" + newFocus);if (newFocus == null && attacheViews.indexOf(newFocus) >= 0) {return;}if (oldFocus == newFocus)return;if (mAnimatorSet != null && mAnimatorSet.isRunning()) {//如果动画正在运行时mAnimatorSet.end();}lastFocus = newFocus;oldLastFocus = oldFocus;mTarget = target;VisibleScope scope = checkVisibleScope(oldFocus, newFocus);if (!scope.isVisible) {return;} else {oldFocus = scope.oldFocus;newFocus = scope.newFocus;oldLastFocus = scope.oldFocus;}if (isScrolling || newFocus == null || newFocus.getWidth() <= 0 || newFocus.getHeight() <= 0)return;mAnimatorList.clear();//清除动画for (FocusListener f : this.mFocusListener) {f.onFocusChanged(oldFocus, newFocus);}} catch (Exception ex) {ex.printStackTrace();}}@Overridepublic void onScrollChanged(View target, View attachView) {try {} catch (Exception ex) {ex.printStackTrace();}}@Overridepublic void onLayout(View target, View attachView) {try {ViewGroup viewGroup = (ViewGroup) attachView.getRootView();if (target.getParent() != null && target.getParent() != viewGroup) {target.setVisibility(View.GONE);if (mFirstFocus)viewGroup.requestFocus();//如果是首次获取焦点,强制变成焦点态}} catch (Exception ex) {ex.printStackTrace();}}protected boolean mFirstFocus = true;public void setFirstFocus(boolean b) {this.mFirstFocus = b;}@Overridepublic void onTouchModeChanged(View target, View attachView, boolean isInTouchMode) {try {if (mEnableTouch && isInTouchMode) {target.setVisibility(View.INVISIBLE);if (lastFocus != null) {AnimatorSet animatorSet = new AnimatorSet();animatorSet.playTogether(getScaleAnimator(lastFocus, false));animatorSet.setDuration(0).start();}}} catch (Exception ex) {ex.printStackTrace();}}protected boolean isScrolling = false;protected List<View> attacheViews = new ArrayList<>();protected Map<View, AdapterView.OnItemSelectedListener> onItemSelectedListenerList = new HashMap<>();@Overridepublic void onAttach(View target, View attachView) {try {mTarget = target;if (target.getParent() != null && (target.getParent() instanceof ViewGroup)) {ViewGroup vg = (ViewGroup) target.getParent();vg.removeView(target);}ViewGroup vg = (ViewGroup) attachView.getRootView();vg.addView(target);target.setVisibility(View.GONE);if (attachView instanceof RecyclerView) {RecyclerView recyclerView = (RecyclerView) attachView;RecyclerView.OnScrollListener recyclerViewOnScrollListener = null;recyclerViewOnScrollListener = new RecyclerView.OnScrollListener() {@Overridepublic void onScrollStateChanged(RecyclerView recyclerView, int newState) {try {super.onScrollStateChanged(recyclerView, newState);if (newState == RecyclerView.SCROLL_STATE_IDLE) {isScrolling = false;View oldFocus = oldLastFocus;View newFocus = lastFocus;VisibleScope scope = checkVisibleScope(oldFocus, newFocus);if (!scope.isVisible) {return;} else {oldFocus = scope.oldFocus;newFocus = scope.newFocus;}AnimatorSet animatorSet = new AnimatorSet();List<Animator> list = new ArrayList<>();list.addAll(getScaleAnimator(newFocus, true));list.addAll(getMoveAnimator(newFocus, 0, 0));animatorSet.setDuration(mDurationTraslate);animatorSet.playTogether(list);animatorSet.start();} else if (newState == RecyclerView.SCROLL_STATE_SETTLING) {isScrolling = true;if (lastFocus != null) {List<Animator> list = getScaleAnimator(lastFocus, false);AnimatorSet animatorSet = new AnimatorSet();animatorSet.setDuration(150);animatorSet.playTogether(list);animatorSet.start();}}} catch (Exception ex) {}}};recyclerView.addOnScrollListener(recyclerViewOnScrollListener);} else if (attachView instanceof AbsListView) {final AbsListView absListView = (AbsListView) attachView;final AdapterView.OnItemSelectedListener onItemSelectedListener = absListView.getOnItemSelectedListener();View temp = null;if (absListView.getChildCount() > 0) {temp = absListView.getChildAt(0);}final View tempFocus = temp;MyOnItemSelectedListener myOnItemSelectedListener = new MyOnItemSelectedListener();myOnItemSelectedListener.onItemSelectedListener = onItemSelectedListener;myOnItemSelectedListener.oldFocus = temp;absListView.setOnItemSelectedListener(myOnItemSelectedListener);onItemSelectedListenerList.put(attachView, myOnItemSelectedListener);}attacheViews.add(attachView);} catch (Exception ex) {ex.printStackTrace();}}protected class MyOnItemSelectedListener implements AdapterView.OnItemSelectedListener {public View oldFocus = null;public View newFocus = null;public AnimatorSet animatorSet;public AdapterView.OnItemSelectedListener onItemSelectedListener;@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {try {if (onItemSelectedListener != null && parent != null) {onItemSelectedListener.onItemSelected(parent, view, position, id);}if (newFocus == null)return;newFocus = view;Rect rect = new Rect();view.getLocalVisibleRect(rect);ViewGroup vg = (ViewGroup) newFocus.getParent();int factorX = 0, factorY = 0;if (Math.abs(rect.left - rect.right) > newFocus.getMeasuredWidth()) {factorX = (Math.abs(rect.left - rect.right) - newFocus.getMeasuredWidth()) / 2 - 1;factorY = (Math.abs(rect.top - rect.bottom) - newFocus.getMeasuredHeight()) / 2;}List<Animator> animatorList = new ArrayList<Animator>(3);animatorList.addAll(getScaleAnimator(newFocus, true));if (oldFocus != null)animatorList.addAll(getScaleAnimator(oldFocus, false));animatorList.addAll(getMoveAnimator(newFocus, factorX, factorY));mTarget.setVisibility(View.VISIBLE);if (animatorSet != null && animatorSet.isRunning())animatorSet.end();animatorSet = new AnimatorSet();animatorSet.setDuration(mDurationTraslate);animatorSet.playTogether(animatorList);animatorSet.start();oldFocus = newFocus;} catch (Exception ex) {ex.printStackTrace();}}@Overridepublic void onNothingSelected(AdapterView<?> parent) {if (onItemSelectedListener != null) {onItemSelectedListener.onNothingSelected(parent);}}}@Overridepublic void OnDetach(View targe, View view) {if (targe.getParent() == view) {((ViewGroup) view).removeView(targe);}attacheViews.remove(view);}public void setEnableTouch(boolean enableTouch) {this.mEnableTouch = enableTouch;}public boolean isScalable() {return mScalable;}public void setScalable(boolean scalable) {this.mScalable = scalable;}public float getScale() {return mScale;}public void setScale(float scale) {this.mScale = scale;}public int getMargin() {return mMargin;}public void setMargin(int mMargin) {this.mMargin = mMargin;}}

MetroViewBorder用于对焦点变化处理及滚动处理

public class MetroViewBorderImpl<X extends View> implements ViewTreeObserver.OnGlobalFocusChangeListener, ViewTreeObserver.OnScrollChangedListener, ViewTreeObserver.OnGlobalLayoutListener, ViewTreeObserver.OnTouchModeChangeListener {private static final String TAG = MetroViewBorderImpl.class.getSimpleName();private ViewGroup mViewGroup;private IMetroViewBorder mMetroViewBorder;private X mView;private View mLastView;public MetroViewBorderImpl(Context context) {this(context, null, 0);}public MetroViewBorderImpl(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MetroViewBorderImpl(Context context, AttributeSet attrs, int defStyleAttr) {init(context, attrs, defStyleAttr);}private void init(Context context, AttributeSet attrs, int defStyleAttr) {mMetroViewBorder = new MetroViewBorderHandler();mView = (X) new View(context, attrs, defStyleAttr);}public MetroViewBorderImpl(X view) {this.mView = view;mMetroViewBorder = new MetroViewBorderHandler();}public MetroViewBorderImpl(X view, IMetroViewBorder border) {this.mView = view;mMetroViewBorder = border;}public MetroViewBorderImpl(Context context, int resId) {this((X) LayoutInflater.from(context).inflate(resId, null, false));}public X getView() {return mView;}public void setBackgroundResource(int resId) {if (mView != null)mView.setBackgroundResource(resId);}@Overridepublic void onScrollChanged() {mMetroViewBorder.onScrollChanged(mView, mViewGroup);}@Overridepublic void onGlobalLayout() {mMetroViewBorder.onLayout(mView, mViewGroup);}@Overridepublic void onTouchModeChanged(boolean isInTouchMode) {mMetroViewBorder.onTouchModeChanged(mView, mViewGroup, isInTouchMode);}@Overridepublic void onGlobalFocusChanged(View oldFocus, View newFocus) {try {if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2) {// 4.3if (oldFocus == null && mLastView != null) {oldFocus = mLastView;}}if (mMetroViewBorder != null)mMetroViewBorder.onFocusChanged(mView, oldFocus, newFocus);mLastView = newFocus;} catch (Exception ex) {ex.printStackTrace();}}public <T extends MetroViewBorderHandler> T getViewBorder() {return (T) mMetroViewBorder;}public void setBorder(IMetroViewBorder border) {this.mMetroViewBorder = border;}public void attachTo(ViewGroup viewGroup) {try {if (viewGroup == null) {if (mView.getContext() instanceof Activity) {Activity activity = (Activity) mView.getContext();viewGroup = (ViewGroup) activity.getWindow().getDecorView().getRootView();//获取顶层view}}if (mViewGroup != viewGroup) {ViewTreeObserver viewTreeObserver = viewGroup.getViewTreeObserver();if (viewTreeObserver.isAlive() && mViewGroup == null) {viewTreeObserver.addOnGlobalFocusChangeListener(this);viewTreeObserver.addOnScrollChangedListener(this);viewTreeObserver.addOnGlobalLayoutListener(this);viewTreeObserver.addOnTouchModeChangeListener(this);}mViewGroup = viewGroup;}mMetroViewBorder.onAttach(mView, viewGroup);} catch (Exception ex) {ex.printStackTrace();}}public void detach() {detachFrom(mViewGroup);}public void detachFrom(ViewGroup viewGroup) {try {if (viewGroup == mViewGroup) {ViewTreeObserver viewTreeObserver = mViewGroup.getViewTreeObserver();//获取view树的观察者viewTreeObserver.removeOnGlobalFocusChangeListener(this);//通知全局性移除相应的listenerviewTreeObserver.removeOnScrollChangedListener(this);viewTreeObserver.removeOnGlobalLayoutListener(this);viewTreeObserver.removeOnTouchModeChangeListener(this);mMetroViewBorder.OnDetach(mView, viewGroup);}} catch (Exception ex) {ex.printStackTrace();}}
}

第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。


这里写图片描述

如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易

http://www.lbrq.cn/news/2613799.html

相关文章:

  • 广州建设银行网站首页2022年免费云服务器
  • 福建电信网站备案长春网站seo公司
  • 网站后台链接怎么做高州新闻 头条 今天
  • d?t网站模版温州seo网站建设
  • wordpress没有备案seo优化网络公司
  • erp软件怎么用搜索引擎优化培训中心
  • 网站备案 停站免费html网站模板
  • 威县网站建设无锡网站制作优化
  • 广州中小学安全教育平台企业整站优化
  • 视频源网站怎么做优化方案的格式及范文
  • 做视频网站seo怎么赚钱
  • wordpress发号系统巢湖seo推广
  • 做ui必要的网站最新最好的磁力搜索
  • 汕头模板建站软件网站seo优化报告
  • 内蒙古住房建设厅网站百度问一问人工客服怎么联系
  • 西安网站建设网络网站域名查询地址
  • 哪类型网站容易做找网络公司做推广费用
  • 重庆永川网站建设价格网站策划方案
  • 怎样重新运行wordpress四川seo推广公司
  • 工程建设信息官方网站做app找什么公司
  • 尤溪网站开发seo交流qq群
  • 如何做网站平台关注站长之家域名查询官网
  • 搜狗网站入口百度seo发包工具
  • 2个网站 同意内容 百度优化百度seo排名公司
  • net做网站杭州seo网站建设靠谱
  • .net和php哪个做网站好网络营销的主要手段
  • 做企业网站前期需要准备什么网络推广宣传方式
  • 做网站 学php哪一部分网络营销的主要特点有哪些
  • 网站独立物流系统查指数
  • 做网站一般注册哪几类商标项目优化seo
  • Nacos配置中心和数据隔离在idea中的实现
  • Lesson 31 Success story
  • 【运维部署篇】OpenShift:企业级容器应用平台全面解析
  • RHCA03--硬件监控及内核模块调优
  • 10-红黑树
  • ZYNQ-按键消抖