周一又到了,是不是感覺一個周末還沒過咋個都沒了呢?既來之則安之,我們還是來學習點有用的,由於之前無意間看到了一個點讚的效果,感覺多麼高大上的,所以想著自己也來實現一下。因此有了此文,如果文中有錯還望各位小夥伴指出出來,自定義View的大佬可以跳過了,(*^__^*) 嘻嘻……
我們還是先看看實現效果:
接下來我們看看實現方法。
分析:
我們可以將這個點讚效果可以分為兩個部分:
點擊部分
我們可以通過attrs自定義的屬性,拿到圖片的Drawable,通過調用drawable.draw(canvas)方法直接畫出來。
上方顯示的動畫部分
第二部分最開始我想到的是直接在上方畫一個TextView,然後設置屬性動畫 達到我們的效果,後來思考這種效果最好不增加自身控制項的大小,假如在上方直接添加TextView那麼必然怎麼整個控制項的高度,很多這種點讚的效果是放在列表中,高度有限。所以我最後想的是使用PopupWindow來實現,然後設置屬性動畫。
我們需要定義的屬性有:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="AgreeView">
<attr name="distance" format="integer"/>
<attr name="from_y" format="integer"/>
<attr name="from_alpha" format="float"/>
<attr name="to_alpha" format="float"/>
<attr name="duration" format="integer"/>
<attr name="text" format="string"/>
<attr name="text_size" format="integer"/>
<attr name="text_color" format="color"/>
<attr name="img" format="reference"/>
<attr name="animation_img" format="reference"/>
<attr name="animation" format="enum">
<enum name="text" value="0"/>
<enum name="img" value="1"/>
</attr>
</declare-styleable>
</resources>
2.我們在構造方法中獲取對應屬性,然後初始化PopupWidow:
private void initPopupWindow() {
mPopupWindow = new PopupWindow();
RelativeLayout layout = new RelativeLayout(mContext);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
tvAnimation = new AppCompatTextView(mContext);
tvAnimation.setIncludeFontPadding(false);
tvAnimation.setTextSize(TypedValue.COMPLEX_UNIT_DIP, text_size);
tvAnimation.setTextColor(text_color);
if (animationMode == ANIMATION_MODE_TEXT) {
tvAnimation.setText(text);
} else {
tvAnimation.setText("");
tvAnimation.setBackgroundDrawable(animalDrawable);
}
tvAnimation.setLayoutParams(layoutParams);
layout.addView(tvAnimation);
mPopupWindow.setContentView(layout);
int w = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
int h = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
tvAnimation.measure(w, h);
mPopupWindow.setWidth(tvAnimation.getMeasuredWidth());
Log.e(TAG, "distance==== " + distance);
mPopupWindow.setHeight(distance + tvAnimation.getMeasuredHeight());
mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
mPopupWindow.setFocusable(false);
mPopupWindow.setTouchable(false);
mPopupWindow.setOutsideTouchable(false);
}
這裡面要注意的是我們要計算PopupWidow的高度和寬度,我們將 RelativeLayout
作為ViewGroup,用 AppCompatTextView作為動畫控制項,如果是圖片則直接設置背景圖片。
3.設置我們點讚View上方的動畫:
private void setPopAnimation() {
mAnimationSet = new AnimationSet(true);
TranslateAnimation translateAnim = new TranslateAnimation(0, 0, from_y, -to_y);
AlphaAnimation alphaAnim = new AlphaAnimation(from_alpha, to_alpha);
mAnimationSet.addAnimation(translateAnim);
mAnimationSet.addAnimation(alphaAnim);
mAnimationSet.setDuration(duration);
mAnimationSet.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (mPopupWindow != null && mPopupWindow.isShowing()) {
new Handler().post(new Runnable() {
@Override
public void run() {
mPopupWindow.dismiss();
}
});
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
4.設置我們點讚圖片的動畫效果:
private void setScaleAnimation() {
ObjectAnimator scaleX = ObjectAnimator.ofFloat(this, "scaleX", 1f, 0.8f, 1.2f, 1f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(this, "scaleY", 1f, 0.8f, 1.2f, 1f);
scaleX.setDuration(duration);
scaleY.setDuration(duration);
scaleX.setInterpolator(new AccelerateDecelerateInterpolator());
scaleY.setInterpolator(new AccelerateDecelerateInterpolator());
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(scaleX).with(scaleY);
animatorSet.start();
}
5.我們onDraw()方法之前我們還需要量測一下我們控制項的大小,假如我們不量測寬高,我們在XML中引用我們的控制項我們自己設定一個寬高,比實際的圖片的寬高要大,最終顯示的圖片還是原圖片大小,不會按照XML中設定的值放大或者縮小。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width;
int height;
int w_mode = MeasureSpec.getMode(widthMeasureSpec);
int w_size = MeasureSpec.getSize(widthMeasureSpec);
int h_mode = MeasureSpec.getMode(heightMeasureSpec);
int h_size = MeasureSpec.getSize(heightMeasureSpec);
if (w_mode == MeasureSpec.AT_MOST || w_mode == MeasureSpec.UNSPECIFIED) {
width = agreeDrawable.getIntrinsicWidth();
} else {
width = w_size;
}
if (h_mode == MeasureSpec.AT_MOST || h_mode == MeasureSpec.UNSPECIFIED) {
height = agreeDrawable.getIntrinsicHeight();
} else {
height = h_size;
}
setMeasuredDimension(width, height);
@SuppressLint("DrawAllocation")
Rect rect = new Rect(0, 0, width, height);
agreeDrawable.setBounds(rect);
}
6.畫我們的圖片:
@Override
protected void onDraw(Canvas canvas) {
agreeDrawable.draw(canvas);
}
7.當我們點擊圖片的時候觸發動畫:
@Override
public void onClick(View v) {
if (mPopupWindow != null && !mPopupWindow.isShowing()) {
int offsetY = -getHeight() - mPopupWindow.getHeight();
mPopupWindow.showAsDropDown(this, getWidth() / 2 - mPopupWindow.getWidth() / 2, offsetY);
mPopupWindow.update();
if (mAnimationSet == null) {
setPopAnimation();
}
tvAnimation.startAnimation(mAnimationSet);
setScaleAnimation();
if (clickListener != null) {
clickListener.onAgreeClick(v);
}
}
}
這裡自定義了一個View的點擊事件方法,供外部調用。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:agreeview="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.lt.agreeview.MainActivity">
<com.lt.agreeview.AgreeView
android:id="@+id/agreeView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
agreeview:animation="text"
agreeview:animation_img="@drawable/ic_favorite_black_24dp"
agreeview:distance="100"
agreeview:from_y="60"
agreeview:layout_constraintBottom_toBottomOf="parent"
agreeview:layout_constraintEnd_toStartOf="@+id/agreeView3"
agreeview:layout_constraintHorizontal_bias="0.5"
agreeview:layout_constraintStart_toStartOf="parent"
agreeview:layout_constraintTop_toTopOf="parent"
agreeview:text="我喜歡你+1"
agreeview:text_color="@color/text_color">
</com.lt.agreeview.AgreeView>
<com.lt.agreeview.AgreeView
android:id="@+id/agreeView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
agreeview:animation="img"
agreeview:animation_img="@drawable/ic_grade_black_24dp"
agreeview:distance="100"
agreeview:from_y="60"
agreeview:layout_constraintBottom_toBottomOf="@+id/agreeView4"
agreeview:layout_constraintEnd_toEndOf="parent"
agreeview:layout_constraintHorizontal_bias="0.5"
agreeview:img="@drawable/ic_grade_black_24dp"
agreeview:layout_constraintStart_toEndOf="@+id/agreeView4"
agreeview:layout_constraintTop_toTopOf="@+id/agreeView4"
agreeview:text_color="@color/text_color">
</com.lt.agreeview.AgreeView>
<android.support.constraint.Group
android:id="@+id/group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</android.support.constraint.ConstraintLayout>
最終我們的實現效果如下:
至此我們的自定義點讚效果就完成了,源碼我已經上傳到Github上面,如果有需要的可以自行下載Github(https://github.com/scorpioLt/AgreeView)
其實自定義View並沒有想得那麼複雜,只要想通了原理,過程一步一步的寫,像這個點讚效果主要就分為:點讚圖片的縮放、向上移動的屬性動畫;上方的動畫用PopupWindow實現,下方直接獲取Drawable畫到Canvas即可。
溫馨提示:
我創建了一個技術交流群,群裡有各個行業的大佬都有,大家可以在群裡暢聊技術方面內容,以及文章推薦;如果有想加入的夥伴加我微信號【luotaosc】備註一下「加群」
另外關注公眾號,還有一些個人收藏的視頻:
回復「Android」 ,獲取Android視頻連結。
回復「Java」 ,獲取Java視頻連結。
回復「C++」 ,獲取C++視頻連結。
回復「C」 ,獲取C視頻連結。
回復「Python」 ,獲取Python視頻連結等等。
原創不易,如果覺得寫得好,掃碼關注一下點個讚,是我最大的動力。
備註:程序圈LT