亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

簡單實用的Android UI微博動態(tài)點贊效果

 更新時間:2016年10月24日 14:09:55   作者:Qiaoidea  
這篇文章主要為大家詳細介紹了簡單實用的Android UI微博動態(tài)點贊效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

說起空間動態(tài)、微博的點贊效果,網上也是很泛濫,各種實現與效果一大堆。而詳細實現的部分,講述的也是參差不齊,另一方面估計也有很多大俠也不屑一顧,覺得完全沒必要單獨開篇來寫和講解吧。畢竟,也就是兩個view和一些簡單的動畫效果罷了。

單若是只講這些,我自然也是不愿花這番功夫的。雖然自己很菜,可也不甘于太菜。所以偶爾看到些好東西,可以延伸學寫下,我還是很情愿拿出來用用,順帶秀一秀逼格什么的。

不扯太多,先說說今天實現點贊效果用到的自以為不錯的兩個點:

Checkable 用來擴展View實現選中狀態(tài)切換

AndroidViewAnimations 基于nineoldandroids封裝的android動畫簡易類庫。究竟有多簡單呢,就像這樣

AnimHelper.with(new PulseAnimator()).duration(1000).playOn(imageView);

作用: 在imageView上使用PulseAnimator這個動畫效果,播放一秒。

當然是從實現角度來看這個庫啦,如果僅僅是使用,google/百度一大堆啦。

結合前兩篇富文本折疊展開,加上我們的點贊view 做出的demo整合效果圖:

1.從實現看門道

其實從效果看無非就是點擊切換圖片,并添加一些簡單動畫效果而已,確實沒什么難度。這里是因為引入了兩個不錯的新內容,使用下,權當新手嘗鮮。

1.1 Checkable接口實現CheckedImageView

系統本身提供了android.widget.Checkable這樣一個接口,方便我們繼承實現View的選中和取消的狀態(tài)。看下這個類:

public interface Checkable {

 /**
 * 設置view的選中狀態(tài)
 */
 void setChecked(boolean checked);

 /**
 * 當前view是否被選中
 */
 boolean isChecked();

 /**
 *改變view的選中狀態(tài)到相反的狀態(tài)
 */
 void toggle();
}

通常這個接口用來幫助我們快速實現view的可選效果,增加了選中和取消兩種狀態(tài)和切換方法。另外為了方便View在狀態(tài)改變時候快速地變看到效果(更背景或圖片),我們可以直接通過selector控制圖片,而其本身并不會自動改變drawable狀態(tài),因此這里還有必要重寫drawableStateChanged方法。我們先以定義一個通用的CheckedImageView為例:

public class CheckedImageView extends ImageView implements Checkable{
 protected boolean isChecked;//選中狀態(tài)
 protected OnCheckedChangeListener onCheckedChangeListener;//狀態(tài)改變事件監(jiān)聽

 public static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };

 public CheckedImageView(Context context) {
 super(context);
 initialize();
 }

 public CheckedImageView(Context context, AttributeSet attrs) {
 super(context, attrs);
 initialize();
 }

 private void initialize() {
 isChecked = false;
 }

 @Override
 public boolean isChecked() {
 return isChecked;
 }

 @Override
 public void setChecked(boolean isChecked) {
 if (this.isChecked != isChecked) {
 this.isChecked = isChecked;
 refreshDrawableState();

 if (onCheckedChangeListener != null) {
 onCheckedChangeListener.onCheckedChanged(this, isChecked);
 }
 }
 }

 @Override
 public void toggle() {//改變狀態(tài)
 setChecked(!isChecked);
 }

 //初始DrawableState時候為它添加一個CHECKED_STATE,ImageView本身是沒有這個狀態(tài)的
 @Override
 public int[] onCreateDrawableState(int extraSpace) {
 int[] states = super.onCreateDrawableState(extraSpace + 1);
 if (isChecked()) {
 mergeDrawableStates(states, CHECKED_STATE_SET);
 }
 return states;
 }

 //當view的選中狀態(tài)被改變的時候通知ImageView改變背景或內容,這個view會自動在drawable狀態(tài)集中選擇與當前狀態(tài)匹配的圖片
 @Override
 protected void drawableStateChanged() {
 super.drawableStateChanged();
 Drawable drawable = getDrawable();
 if (drawable != null) {
 int[] myDrawableState = getDrawableState();
 drawable.setState(myDrawableState);
 invalidate();
 }
 }

 //設置狀態(tài)改變監(jiān)聽事件
 public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) {
 this.onCheckedChangeListener = onCheckedChangeListener;
 }

 //當選中狀態(tài)改變時監(jiān)聽接口觸發(fā)該事件
 public static interface OnCheckedChangeListener {
 public void onCheckedChanged(CheckedImageView checkedImgeView, boolean isChecked);
 }
}

這是一個通用的可被選中ImageView,當點擊之后被選中,再次點擊則取消。而其背景/內容也會隨之改變。比如下圖所示效果:

從代碼上看,我們本身并沒有直接定義當view點擊之后,調用setImage()或者setBackground()來改變內容,而是通過使用View本身的DrawableState來繪制和更改,查找與它對應匹配的圖片,而這些狀態(tài)所對應的圖片,都預先在selector中配置好。關于selector這里不做介紹,自行查閱學習。   

既然提到selector,順帶提下之前遇到的坑,關于他的匹配原則。比如下邊這樣一個selector:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
 <item android:state_pressed="true" android:drawable="@drawable/icon_pressed"></item>
 <item android:state_checked="true" android:drawable="@drawable/icon_checked"></item>
 <item android:drawable="@drawable/icon_normal"></item>
</selector>

當view同時有上邊兩個狀態(tài)(如state_pressed和state_checked)的時候,view優(yōu)先顯示第一個狀態(tài)時候的圖片(icon_pressed)。這是因為它是由上到下有序查找的,當找到第一個狀態(tài)與他定義的所相符所在行時,就優(yōu)先顯示這行的圖片。所以當我們將最后一行

< item android:drawable=”@drawable/icon_normal”>< /item>

放在第一行時,無論是否選中狀態(tài)或按下狀態(tài),都顯示的是icon_normal。初學者一定要注意,我當初就因為這個原因耗費了很多時間查找緣由。

回到我們的點贊實現。這里實現的點贊View PraiseView 包含了一個 CheckedImageView 和一個 TextView ,點贊之后,ImageView會放大回縮并彈出一個TextView”+1”的動畫效果。

public class PraiseView extends FrameLayout implements Checkable{//同樣繼承Checkable
 protected OnPraisCheckedListener praiseCheckedListener;
 protected CheckedImageView imageView; //點贊圖片
 protected TextView textView; //+1
 protected int padding;

 public PraiseView(Context context) {
 super(context);
 initalize();
 }

 public PraiseView(Context context, AttributeSet attrs) {
 super(context, attrs);
 initalize();
 }

 protected void initalize() {
 setClickable(true);
 imageView = new CheckedImageView(getContext());
 imageView.setImageResource(R.drawable.blog_praise_selector);
 FrameLayout.LayoutParams flp = new LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT,Gravity.CENTER);
 addView(imageView, flp);

 textView = new TextView(getContext());
 textView.setTextSize(10);
 textView.setText("+1");
 textView.setTextColor(Color.parseColor("#A24040"));
 textView.setGravity(Gravity.CENTER);
 addView(textView, flp);
 textView.setVisibility(View.GONE);
 }

 @Override
 public boolean performClick() {
 checkChange();
 return super.performClick();
 }

 @Override
 public void toggle() {
 checkChange();
 }

 public void setChecked(boolean isCheacked) {
 imageView.setChecked(isCheacked);
 }

 public void checkChange() {//點擊切換狀態(tài)
 if (imageView.isChecked) {
 imageView.setChecked(false);
 } else {
 imageView.setChecked(true);
 textView.setVisibility(View.VISIBLE);
 //放大動畫
 AnimHelper.with(new PulseAnimator()).duration(1000).playOn(imageView);
 //飄 “+1”動畫
 AnimHelper.with(new SlideOutUpAnimator()).duration(1000).playOn(textView);
 }
 //調用點贊事件
 if (praiseCheckedListener != null) {
 praiseCheckedListener.onPraisChecked(imageView.isChecked);
 }
 }

 public boolean isChecked() {
 return imageView.isChecked;
 }

 public void setOnPraisCheckedListener(OnPraisCheckedListener praiseCheckedListener) {
 this.praiseCheckedListener = praiseCheckedListener;
 }

 public interface OnPraisCheckedListener{
 void onPraisChecked(boolean isChecked);
 }
}

過于自定的View大概就這么多了,Checkable這個小巧方便的類,不知道你會用了沒。至于上邊用到的兩個動畫效果集:

AnimHelper.with(new PulseAnimator()).duration(1000).playOn(imageView);
AnimHelper.with(new SlideOutUpAnimator()).duration(1000).playOn(textView);

感覺封裝的挺簡潔實用,所以很有必要學習分析一下。

1.2 動畫庫的封裝和快速框架

提到動畫,Android本身自帶的動畫類Animation已經做到支持3.0及以上了,雖然也做了很好的封裝,但是做起復雜動畫來還是不夠像上邊那樣簡潔。在關于動畫兼容方面,github上的大牛Jake Wharton又做了一套動畫開源庫NineOldAndroids,效果很好而且支持3.0級以前的版本,確實很值得稱贊。而在此基礎上,有很多高手又做了二次封裝,實現了復雜動畫,同時保證方便簡潔,而且通用性和擴展性更高。我們這里的動畫使用的就是這樣一個簡單的封裝。

比如,要在XXView上時用XXAnimator這樣的動畫,持續(xù)Duration秒。就這么一行代碼:

AnimHelper.with(new SlideOutUpAnimator()).duration(1000).playOn(textView);

來看一下基于NineOldAndroids的ViewAnimations具體實現。

1). 首先定義一個基本動畫效果類BaseViewAnimator

這個BaseViewAnimator動畫類使用一個動畫集合AnimatorSet,包裝成單個動畫類似的用法,并定義了一個abstract方法prepare():

 public abstract class BaseViewAnimator {

 public static final long DURATION = 1000;

 private AnimatorSet mAnimatorSet;
 private long mDuration = DURATION;

 {
 mAnimatorSet = new AnimatorSet();
 }


 protected abstract void prepare(View target);

 public BaseViewAnimator setTarget(View target) {
 reset(target);
 prepare(target);
 return this;
 }

 public void animate() {
 start();
 }

 /**
 * reset the view to default status
 *
 * @param target
 */
 public void reset(View target) {
 ViewHelper.setAlpha(target, 1);
 ViewHelper.setScaleX(target, 1);
 ViewHelper.setScaleY(target, 1);
 ViewHelper.setTranslationX(target, 0);
 ViewHelper.setTranslationY(target, 0);
 ViewHelper.setRotation(target, 0);
 ViewHelper.setRotationY(target, 0);
 ViewHelper.setRotationX(target, 0);
 ViewHelper.setPivotX(target, target.getMeasuredWidth() / 2.0f);
 ViewHelper.setPivotY(target, target.getMeasuredHeight() / 2.0f);
 }

 /**
 * start to animate
 */
 public void start() {
 mAnimatorSet.setDuration(mDuration);
 mAnimatorSet.start();
 }

 public BaseViewAnimator setDuration(long duration) {
 mDuration = duration;
 return this;
 }

 public BaseViewAnimator setStartDelay(long delay) {
 getAnimatorAgent().setStartDelay(delay);
 return this;
 }

 public long getStartDelay() {
 return mAnimatorSet.getStartDelay();
 }

 public BaseViewAnimator addAnimatorListener(AnimatorListener l) {
 mAnimatorSet.addListener(l);
 return this;
 }

 public void cancel(){
 mAnimatorSet.cancel();
 }

 public boolean isRunning(){
 return mAnimatorSet.isRunning();
 }

 public boolean isStarted(){
 return mAnimatorSet.isStarted();
 }

 public void removeAnimatorListener(AnimatorListener l) {
 mAnimatorSet.removeListener(l);
 }

 public void removeAllListener() {
 mAnimatorSet.removeAllListeners();
 }

 public BaseViewAnimator setInterpolator(Interpolator interpolator) {
 mAnimatorSet.setInterpolator(interpolator);
 return this;
 }

 public long getDuration() {
 return mDuration;
 }

 public AnimatorSet getAnimatorAgent() {
 return mAnimatorSet;
 }

}

復雜動畫效果基類BaseViewAnimator使用一個AnimatorSet集合來添加各種動畫 ,并綁定到目標targetView ,使用 prepare(View target) 的abstract方法供其子類實現具體的動畫效果。   

2). 其次基于這個類實現我們的各種動畫效果XXAnimator

當我們要實現具體的動畫效果時,可以直接繼承這個類并實現prepaer方法。比如這里定義的上劃消失SlideOutUpAnimator 和放大回縮動畫PulseAnimator

/**
*上劃消失(飄+1)
*/
public class SlideOutUpAnimator extends BaseViewAnimator {
 @Override
 public void prepare(View target) {
 ViewGroup parent = (ViewGroup)target.getParent();
 getAnimatorAgent().playTogether(
 ObjectAnimator.ofFloat(target, "alpha", 1, 0),
 ObjectAnimator.ofFloat(target,"translationY",0,-parent.getHeight()/2)
 );
 }
}

/**
*放大效果
*/
public class PulseAnimator extends BaseViewAnimator {
 @Override
 public void prepare(View target) {
 getAnimatorAgent().playTogether(
 ObjectAnimator.ofFloat(target, "scaleY", 1, 1.2f, 1),
 ObjectAnimator.ofFloat(target, "scaleX", 1, 1.2f, 1)
 );
 }
}

上邊兩種動畫效果就是對BaseViewAnimator的兩種實現,動畫本身使用的庫是NineOldAndroids。

3). 最后封裝一個動畫管理工具類AnimHelper供外部使用

首先定義了一個靜態(tài)類,使用helper來實例化這個靜態(tài)類,并設置各個參數選項。

 public class AnimHelper {
 private static final long DURATION = BaseViewAnimator.DURATION;
 private static final long NO_DELAY = 0;

 /**
 *實例化得到AnimationComposer的唯一接口
 */
 public static AnimationComposer with(BaseViewAnimator animator) {
 return new AnimationComposer(animator);
 }

 /**
 *定義與動畫效果相關聯的各種參數,
 *使用這種方法可以保證對象的構建和他的表示相互隔離開來
 */
 public static final class AnimationComposer {

 private List<Animator.AnimatorListener> callbacks = new ArrayList<Animator.AnimatorListener>();

 private BaseViewAnimator animator;
 private long duration = DURATION;
 private long delay = NO_DELAY;
 private Interpolator interpolator;
 private View target;

 private AnimationComposer(BaseViewAnimator animator) {
 this.animator = animator;
 }

 public AnimationComposer duration(long duration) {
 this.duration = duration;
 return this;
 }

 public AnimationComposer delay(long delay) {
 this.delay = delay;
 return this;
 }

 public AnimationComposer interpolate(Interpolator interpolator) {
 this.interpolator = interpolator;
 return this;
 }


 public AnimationComposer withListener(Animator.AnimatorListener listener) {
 callbacks.add(listener);
 return this;
 }

 public AnimManager playOn(View target) {
 this.target = target;
 return new AnimManager(play(), this.target);
 }

 private BaseViewAnimator play() {
 animator.setTarget(target);
 animator.setDuration(duration)
 .setInterpolator(interpolator)
 .setStartDelay(delay);

 if (callbacks.size() > 0) {
 for (Animator.AnimatorListener callback : callbacks) {
 animator.addAnimatorListener(callback);
 }
 }

 animator.animate();
 return animator;
 }
 }

 /**
 *動畫管理類
 */
 public static final class AnimManager{

 private BaseViewAnimator animator;
 private View target;

 private AnimManager(BaseViewAnimator animator, View target){
 this.target = target;
 this.animator = animator;
 }

 public boolean isStarted(){
 return animator.isStarted();
 }

 public boolean isRunning(){
 return animator.isRunning();
 }

 public void stop(boolean reset){
 animator.cancel();

 if(reset)
 animator.reset(target);
 }
 }

}

這段代碼使用了類似Dialog的builder模式,感興趣的可以搜一下 JAVA設計模式-Builder.晚點會另開一篇講解。

(注: 復雜動畫這一部分的內容這里只是拿出來展示和使用,包裝和實現是由代碼家大大原創(chuàng),有想了解更多動畫及效果的請點其名字鏈接)

運行一下,就可以看到前面所演示的效果了。點擊第一下,伴隨著圖標變大一下并飄出“+1”的效果,圖片切換到選中狀態(tài);再點則恢復未選中,而且不會觸發(fā)動畫。

至此,點贊這塊內容和關注點也說完了,希望各位能有點兒收獲,另外便于自己也能加深理解。

最后,附上示例源碼地址:Android UI微博動態(tài)點贊

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • 使用Chrome瀏覽器調試Android App詳解

    使用Chrome瀏覽器調試Android App詳解

    這篇文章主要介紹了使用Chrome瀏覽器調試Android App詳解,本網講解了使用Facebook開源Stetho實現在Chrome中調試Android App中,需要的朋友可以參考下
    2015-05-05
  • Android制作簡單垂直上拉下滑View效果

    Android制作簡單垂直上拉下滑View效果

    這篇文章主要介紹了Android制作簡單垂直上拉下滑View效果的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • Android Drawerlayout側拉欄事件傳遞問題的解決方法

    Android Drawerlayout側拉欄事件傳遞問題的解決方法

    這篇文章主要為大家詳細介紹了Android Drawerlayout側拉欄事件傳遞問題的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Android ADT和SDK Manager無法更新下載解決方案

    Android ADT和SDK Manager無法更新下載解決方案

    這篇文章主要介紹了Android ADT和SDK Manager無法更新下載解決方案的相關資料,需要的朋友可以參考下
    2017-04-04
  • Android開發(fā)OkHttp執(zhí)行流程源碼分析

    Android開發(fā)OkHttp執(zhí)行流程源碼分析

    這篇文章主要為大家介紹了Android開發(fā)OkHttp執(zhí)行流程源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • Android?Studio使用自定義對話框效果

    Android?Studio使用自定義對話框效果

    這篇文章主要為大家詳細介紹了Android?Studio使用自定義對話框效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Android 7.0開發(fā)獲取存儲設備信息的方法

    Android 7.0開發(fā)獲取存儲設備信息的方法

    這篇文章主要介紹了Android 7.0開發(fā)獲取存儲設備信息的方法,結合實例形式分析了Android7.0針對存儲設備信息的獲取、判斷操作方法與相關注意事項,需要的朋友可以參考下
    2017-11-11
  • Android獲得內/外置存儲卡路徑的方法

    Android獲得內/外置存儲卡路徑的方法

    我們知道Android上一般都有外置的存儲卡,內置存儲卡路徑大家都知道怎么獲得的。那么如何獲取外置存儲卡的位置呢?下面小編通過本文給大家分享下
    2017-01-01
  • 在android開發(fā)中盡量不要使用中文路徑的問題詳解

    在android開發(fā)中盡量不要使用中文路徑的問題詳解

    本篇文章對在android開發(fā)中盡量不要使用中文路徑的問題進行了詳細的分析介紹。需要的朋友參考下
    2013-05-05
  • Kotlin淺析null操作方法

    Kotlin淺析null操作方法

    Kotlin對比于Java的一個最大的區(qū)別就是它致力于消除空引用所帶來的危險。在Java中,如果我們嘗試訪問一個空引用的成員可能就會導致空指針異常NullPointerException(NPE)的出現。在Kotlin語言中就解決了這個問題,下面來看看它是如何做到的
    2022-08-08

最新評論