간단 하고 실 용적 인 Android UI 웨 이 보 동적 좋아요 효과

공간 동태,웨 이 보 의 좋아요 효과 에 대해 말하자면 인터넷 도 범람 하고 각종 실현 과 효과 가 많다.그리고 상세 하 게 이 루어 진 부분 도 들쭉날쭉 하고 다른 한편 으로 는 협객 들 도 거들 떠 보지 도 않 을 것 이 라 고 생각 합 니 다.따로 시작 해서 쓰 고 설명 할 필요 가 전혀 없다 고 생각 합 니 다.결국 두 개의 view 와 간단 한 애니메이션 효과 일 뿐이다.
단지 이런 것 만 말한다 면 나 도 당연히 이런 공 을 들 이 고 싶 지 않다.비록 자신 은 매우 요리 하지만 너무 요리 하 는 것 을 달가워 하지 않 는 다.그래서 가끔 좋 은 것 을 볼 수 있 고 연장 학 으로 쓸 수 있 습 니 다.저 는 꺼 내 서 사용 하고 싶 습 니 다.
많이 말 하지 않 고 오늘 좋아요 효 과 를 실현 하 는 데 사용 되 는 자신 이 괜찮다 고 생각 하 는 두 가지 점 을 먼저 말 해 보 세 요.
Checkable 은 View 를 확장 하여 선택 한 상태 전환 을 실현 합 니 다.
AndroidView Animations 는 나 인 올 드 안 드 로 이 드 를 기반 으로 한 안 드 로 이 드 애니메이션 간이 라 이브 러 리 입 니 다.얼마나 쉬 운 지 이렇게
AnimHelper.with(new PulseAnimator()).duration(1000).playOn(imageView);
역할:imageView 에서 Pulse Animator 라 는 애니메이션 효 과 를 사용 하여 1 초 재생 합 니 다.
당연히 실현 적 인 측면 에서 볼 때 이 라 이브 러 리 는 단지 사용 만 한다 면 구 글/바 이 두 는 한 무더기 가 될 것 이다.
앞의 두 편의 부텍스트 접 기 전개와 우리 의 좋아요 view 를 결합 하여 만 든 demo 통합 효과 도:

1.실현 에서 비결 을 본다
사실은 효 과 를 보면 그림 전환 을 클릭 하고 간단 한 애니메이션 효 과 를 추가 하 는 것 일 뿐 어렵 지 않다.좋 은 새로운 콘 텐 츠 두 가 지 를 도 입 했 기 때문에 초보 자로 서 맛 을 볼 수 있 기 때문이다.
1.1 Checkable 인터페이스 CheckedImageView 구현
시스템 자체 가 android.widget.Checkable 이라는 인 터 페 이 스 를 제공 하여 View 의 선택 과 취 소 를 실현 하 는 상 태 를 계승 할 수 있 습 니 다.이 종 류 를 보 세 요.

public interface Checkable {

 /**
 *   view     
 */
 void setChecked(boolean checked);

 /**
 *   view     
 */
 boolean isChecked();

 /**
 *  view           
 */
 void toggle();
}
보통 이 인 터 페 이 스 는 view 의 선택 효 과 를 빠르게 실현 하 는 데 도움 을 주 고 선택 과 취소 두 가지 상태 와 전환 방법 을 추가 합 니 다.또한 View 가 상태 가 바 뀔 때 효과(더 배경 이나 그림)를 빠르게 볼 수 있 도록 selector 를 통 해 그림 을 직접 제어 할 수 있 으 며,그 자체 가 drawable 상 태 를 자동 으로 바 꾸 지 않 기 때문에 drawable State Changed 방법 을 다시 쓸 필요 가 있 습 니 다.우 리 는 먼저 일반적인 CheckedImageView 를 정의 합 니 다.

public class CheckedImageView extends ImageView implements Checkable{
 protected boolean isChecked;//    
 protected OnCheckedChangeListener onCheckedChangeListener;//        

 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() {//    
 setChecked(!isChecked);
 }

 //  DrawableState        CHECKED_STATE,ImageView          
 @Override
 public int[] onCreateDrawableState(int extraSpace) {
 int[] states = super.onCreateDrawableState(extraSpace + 1);
 if (isChecked()) {
 mergeDrawableStates(states, CHECKED_STATE_SET);
 }
 return states;
 }

 // view             ImageView       ,  view    drawable                
 @Override
 protected void drawableStateChanged() {
 super.drawableStateChanged();
 Drawable drawable = getDrawable();
 if (drawable != null) {
 int[] myDrawableState = getDrawableState();
 drawable.setState(myDrawableState);
 invalidate();
 }
 }

 //          
 public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) {
 this.onCheckedChangeListener = onCheckedChangeListener;
 }

 //                 
 public static interface OnCheckedChangeListener {
 public void onCheckedChanged(CheckedImageView checkedImgeView, boolean isChecked);
 }
}
이것 은 선택 할 수 있 는 일반적인 ImageView 입 니 다.클릭 한 후에 선택 되 고 다시 클릭 하면 취소 합 니 다.그 배경/내용 도 달라 진다.예 를 들 어 다음 그림 에서 보 여 준 효과:

코드 상 으로 는 view 가 클릭 한 후에 setImage()나 setBackground()를 사용 하여 내용 을 바 꾸 는 것 을 직접적 으로 정의 하지 않 고 View 자체 의 DrawableState 를 사용 하여 그림 을 그리고 변경 하 며 이에 대응 하 는 그림 을 찾 습 니 다.이러한 상태 에 대응 하 는 그림 은 모두 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 가 동시에 위의 두 상태 가 있 을 때(예 를 들 어 statepressed 와 statechecked)일 때 view 는 첫 번 째 상태의 그림 을 우선 표시 합 니 다(iconpressed)。이것 은 위 에서 아래로 질서 있 게 찾 았 기 때 문 입 니 다.첫 번 째 상태 가 그 가 정의 한 줄 과 일치 하 는 줄 을 찾 았 을 때 이 줄 의 그림 을 우선 표시 합 니 다.그래서 우리 가 마지막 줄 을
< item android:drawable=”@drawable/icon_normal”>< /item>
첫 줄 에 놓 을 때 상 태 를 선택 하 든 누 르 든 상 태 는 icon 로 표 시 됩 니 다.normal。초보 자 는 반드시 주의해 야 한다.나 는 당초에 이 때문에 많은 시간 을 들 여 이 유 를 찾 았 다.
우리 의'좋아요'로 돌아 가 이 루어 진다.여기 서 이 루어 진'좋아요'View PraiseView 는 Checked ImageView 와'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() {//      
 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 애니메이션 라 이브 러 리 의 패키지 와 빠 른 프레임 워 크
애니메이션 에 대해 말하자면 안 드 로 이 드 자체 가 가지 고 있 는 애니메이션 류 Animation 은 3.0 이상 을 지원 했다.좋 은 패 키 징 도 했 지만 복잡 한 애니메이션 을 만 드 는 것 은 위 처럼 간결 하지 않다.애니메이션 호환성 에 있어 github 의 큰 소 Jake Wharton 은 애니메이션 오픈 소스 라 이브 러 리 Nine Old Androids 를 만 들 었 는데 효과 가 좋 고 3.0 급 이전 버 전 을 지원 하 니 정말 칭찬 할 만하 다.이 를 바탕 으로 많은 고수 들 이 두 번 의 패 키 징 을 하여 복잡 한 애니메이션 을 실현 하 는 동시에 편리 하고 간결 하 며 유 니 버 설 성과 확장 성 이 더욱 높다.우리 가 있 는 이곳 의 애니메이션 은 바로 이런 간단 한 포장 을 사용한다.
예 를 들 어 XXView 에서 XXAnimator 와 같은 애니메이션 으로 Duration 초 를 지속 해 야 한다.이렇게 한 줄 의 코드:
AnimHelper.with(new SlideOutUpAnimator()).duration(1000).playOn(textView);
나 인 올 드 안 드 로 이 드 를 기반 으로 한 뷰 애 니 메 이 션 스 의 구체 적 인 실현 을 살 펴 보 자.
1).먼저 기본 애니메이션 효과 클래스 BaseView Animator 를 정의 합 니 다.
이 BaseView Animator 애니메이션 클래스 는 애니메이션 집합 Animator Set 을 사용 하여 하나의 애니메이션 과 유사 한 용법 으로 포장 하고 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;
 }

}
복잡 한 애니메이션 효과 기본 클래스 BaseView Animator 는 하나의 Animator Set 집합 을 사용 하여 각종 애니메이션 을 추가 하고 목표 targetView 에 연결 하 며 prepare(View target)의 abstract 방법 으로 하위 클래스 가 구체 적 인 애니메이션 효 과 를 실현 하도록 합 니 다.  
2).그 다음 에 이런 유형 을 바탕 으로 우리 의 각종 애니메이션 효 과 를 실현 한다.XXAnimator
우리 가 구체 적 인 애니메이션 효 과 를 실현 하려 면 이 유형 을 직접 계승 하여 prepaer 방법 을 실현 할 수 있다.예 를 들 어 여기 서 정 의 된 위 에 슬라이드 아웃 애 니 메 이 터 가 사라 지고 확대 애니메이션 Pulse Animater 가 있 습 니 다.

/**
*    ( +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)
 );
 }
}
위의 두 가지 애니메이션 효 과 는 바로 BaseView Animator 에 대한 두 가지 실현 이다.애니메이션 자체 가 사용 하 는 라 이브 러 리 는 Nine Old Androids 이다.
3).마지막 으로 외부 에서 사용 할 수 있 도록 애니메이션 관리 도구 류 AnimHelper 를 패키지 합 니 다.
먼저 정적 클래스 를 정의 하고 helper 를 사용 하여 정적 클래스 를 예화 하 며 각 매개 변수 옵션 을 설정 합 니 다.

 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 를 찾 아 보 세 요.나중에 따로 설명 하 겠 습 니 다.
(주:복잡 한 애니메이션 이라는 부분의 내용 은 여기 서 꺼 내 서 전시 하고 사용 할 뿐 입 니 다.포장 과 실현 은 코드 가 에 의 해 크게 창작 되 었 습 니 다.더 많은 애니메이션 과 효 과 를 알 고 싶 은 분 은 이름 을 눌 러 링크 하 십시오)
실행 하면 앞에서 보 여 준 효 과 를 볼 수 있 습 니 다.첫 번 째 를 클릭 하면 아이콘 이 커지 고'+1'효과 가 나타 나 며 그림 이 선택 한 상태 로 전 환 됩 니 다.다시 누 르 면 선택 되 지 않 은 것 을 복원 하고 애니메이션 을 실행 하지 않 습 니 다.
이로써'좋아요'라 는 내용 과 관심 사 에 대해 서도 말씀 드 렸 습 니 다.여러분 들 이 뭔 가 얻 은 것 이 있 고 자신 도 이해 할 수 있 기 를 바 랍 니 다.
마지막 으로 예시 원본 주소 첨부:Android UI 웨 이 보 동적 좋아요
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기