안 드 로 이 드 개발 시 뮬 레이 터 선물 효과
수요 분석
전체 애니메이션 이 몇 부분 으로 구성 되 어 있 는 것 을 볼 수 있다.그러면 우 리 는 모든 부분 을 나 누 어 각각 격파 할 것 이다.
1.그 내용 과 내용 간 의 위치 관 계 를 표시 하 시 겠 습 니까?
사용자 프로필,닉네임,선물 아이콘,수량 을 표시 할 수 있 습 니 다.그래서 여 기 는 FrameLayout 를 루트 레이아웃 으로 선택 하 겠 습 니 다.
2.어떤 애니메이션 과 애니메이션 의 실행 순서 가 필요 합 니까?
a.먼저 전체적으로 왼쪽 에서 오른쪽으로 날 아 들 어가 고 리 턴(translationX+Overshoot Interpolator)이 있 습 니 다.
b.그리고 선물 은 왼쪽 에서 오른쪽으로 날 아가 감속 효과 가 있 는(translationX+Decelerate Interpolator)
c.선물 수량 을 순서대로 누적 하 는 동시에 크기 조정(scale+repeat)
d.뒤의 입자 효과(프레임 애니메이션)
e.전체적으로 위로 이동 하고 점점 사라 집 니 다(translation Y+alpha)
3.선물 을 보 내 는 구역 은 두 개(A,B)인 데 어떻게 분배 하나 요?
사용자 가 선물 을 보 내 는 수량 이 일정 하지 않 기 때문에 애니메이션 이 지속 되 는 시간 도 일정 하지 않다.그러나 우 리 는 이 두 구역 이 충분히 사용 되 기 를 바 랍 니 다.즉,우 리 는 이 선물 인 스 턴 스 를 저장 하 는 대기 열 이 필요 합 니 다.A 와 B 가 남 은 사람 이 누구 에 게 처리 해 야 합 니까?
4.상기 모든 내용 은 원생 의 공간 을 사용 하면 이 루어 질 수 있 습 니까?
위의 분석 과 같이 우 리 는 때때로 전 체 를 조작 하고,때로는 부분 을 조작한다.이때 우 리 는 FrameLayout 를 계승 하 는 레이아웃 을 사용자 정의 하 는 것 이 좋 습 니 다.사실은 한 층 을 포장 하 는 것 입 니 다.그러면 우 리 는 전체 레이아웃 을 잘 제어 할 수 있 습 니 다.그 밖 에 우 리 는 선물 수량 이 묘사 되 어 있 는 것 을 알 게 되 었 는데,우리 가 사용자 정의 로 실현 해 야 할 것 같다.
기능 실현
수요 분석 이 끝 났 으 니 다음은 기능 의 실현 에 대해 이야기 합 시다.
우선 우리 의 전체적인 구 조 를 때 리 겠 습 니 다.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/animation_person_rl"
android:layout_width="wrap_content"
android:layout_height="39dp"
android:layout_gravity="left"
android:layout_marginTop="22dp"
android:background="@drawable/bg_giftlayout">
<ImageView
android:id="@+id/gift_userheader_iv"
android:layout_width="39dp"
android:layout_height="39dp"
android:layout_margin="3dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:src="@mipmap/ember" />
<TextView
android:id="@+id/gift_usernickname_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginTop="4dp"
android:layout_toRightOf="@id/gift_userheader_iv"
android:text=" "
android:textColor="#ffffff"
android:textSize="12sp" />
<TextView
android:id="@+id/gift_usersign_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/gift_usernickname_tv"
android:layout_below="@id/gift_usernickname_tv"
android:layout_marginTop="4dp"
android:ellipsize="end"
android:text=" "
android:textColor="#ffea79"
android:textSize="11sp" />
<ImageView
android:id="@+id/animation_gift"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/gift_usersign_tv"
android:background="@mipmap/diamond2x" />
</RelativeLayout>
<ImageView
android:id="@+id/animation_light"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="120dp"
android:src="@drawable/light_star_anim" />
<com.example.work.animationdemo.StrokeTextView
android:id="@+id/animation_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="185dp"
android:layout_marginTop="12dp"
android:text="x 1"
android:textColor="#0076ff"
android:textSize="24sp"
app:innnerColor="#ffffff"
app:outerColor="#0076ff" />
</FrameLayout>
여 기 는 간단 합 니 다.더 이상 말 하지 않 겠 습 니 다.Stroke TextView 에 중심 을 두 고 테 두 리 를 그 리 는 textview 를 보 세 요.사실은 ondraw 방법 을 다시 써 서 먼저 바깥쪽 을 그리고 안쪽 을 그 리 는 것 입 니 다.
@Override
protected void onDraw(Canvas canvas) {
if (m_bDrawSideLine) {
//
setTextColorUseReflection(mOuterColor);
m_TextPaint.setStrokeWidth(5);
m_TextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
super.onDraw(canvas);
// ,
setTextColorUseReflection(mInnerColor);
m_TextPaint.setStrokeWidth(0);
m_TextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
super.onDraw(canvas);
}
/**
*
* @param color
*/
private void setTextColorUseReflection(int color) {
Field textColorField;
try {
textColorField = TextView.class.getDeclaredField("mCurTextColor");
textColorField.setAccessible(true);
textColorField.set(this, color);
textColorField.setAccessible(false);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
m_TextPaint.setColor(color);
}
선물의 실체 클래스 정의
public class GiftSendModel {
private int giftCount;
private String userAvatarRes;
private String nickname;
private String sig;
private int giftRes;
private String gift_id;
private int star;
public GiftSendModel(int giftCount) {
this.giftCount = giftCount;
}
public int getGiftCount() {
return giftCount;
}
public void setGiftCount(int giftCount) {
this.giftCount = giftCount;
}
......
패키지 전체 레이아웃
public class GiftFrameLayout extends FrameLayout {
private LayoutInflater mInflater;
RelativeLayout anim_rl;
ImageView anim_gift, anim_light, anim_header;
TextView anim_nickname, anim_sign;
StrokeTextView anim_num;
/**
*
*/
int starNum = 1;
int repeatCount = 0;
private boolean isShowing = false;
public GiftFrameLayout(Context context) {
this(context, null);
}
public GiftFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mInflater = LayoutInflater.from(context);
initView();
}
private void initView() {
View view = mInflater.inflate(R.layout.animation, this, false);
anim_rl = (RelativeLayout) view.findViewById(R.id.animation_person_rl);
anim_gift = (ImageView) view.findViewById(R.id.animation_gift);
anim_light = (ImageView) view.findViewById(R.id.animation_light);
anim_num = (StrokeTextView) view.findViewById(R.id.animation_num);
anim_header = (ImageView) view.findViewById(R.id.gift_userheader_iv);
anim_nickname = (TextView) view.findViewById(R.id.gift_usernickname_tv);
anim_sign = (TextView) view.findViewById(R.id.gift_usersign_tv);
this.addView(view);
}
public void hideView() {
anim_gift.setVisibility(INVISIBLE);
anim_light.setVisibility(INVISIBLE);
anim_num.setVisibility(INVISIBLE);
}
public void setModel(GiftSendModel model){
if (0!=model.getGiftCount()) {
this.repeatCount = model.getGiftCount();
}
if (!TextUtils.isEmpty(model.getNickname())) {
anim_nickname.setText(model.getNickname());
}
if (!TextUtils.isEmpty(model.getSig())) {
anim_sign.setText(model.getSig());
}
}
public boolean isShowing(){
return isShowing;
}
public AnimatorSet startAnimation( final int repeatCount) {
hideView();
//
ObjectAnimator flyFromLtoR = GiftAnimationUtil.createFlyFromLtoR(anim_rl, -getWidth(), 0, 400,new OvershootInterpolator());
flyFromLtoR.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
GiftFrameLayout.this.setVisibility(View.VISIBLE);
GiftFrameLayout.this.setAlpha(1f);
isShowing = true;
anim_num.setText("x " + 1);
Log.i("TAG", "flyFromLtoR A start");
}
});
//
ObjectAnimator flyFromLtoR2 = GiftAnimationUtil.createFlyFromLtoR(anim_gift, -getWidth(), 0, 400,new DecelerateInterpolator());
flyFromLtoR2.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
anim_gift.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animator animation) {
GiftAnimationUtil.startAnimationDrawable(anim_light);
anim_num.setVisibility(View.VISIBLE);
}
});
//
ObjectAnimator scaleGiftNum = GiftAnimationUtil.scaleGiftNum(anim_num, repeatCount);
scaleGiftNum.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationRepeat(Animator animation) {
anim_num.setText("x " + (++starNum));
}
});
//
ObjectAnimator fadeAnimator = GiftAnimationUtil.createFadeAnimator(GiftFrameLayout.this, 0, -100, 300, 400);
fadeAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
GiftFrameLayout.this.setVisibility(View.INVISIBLE);
}
});
//
ObjectAnimator fadeAnimator2 = GiftAnimationUtil.createFadeAnimator(GiftFrameLayout.this, 100, 0, 20, 0);
AnimatorSet animatorSet = GiftAnimationUtil.startAnimation(flyFromLtoR, flyFromLtoR2, scaleGiftNum, fadeAnimator, fadeAnimator2);
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
starNum = 1;
isShowing = false;
}
});
return animatorSet;
저 희 는 모든 애니메이션 방법 을 Gift Animation Util 에 적어 서 관리 하기 편 합 니 다.
public class GiftAnimationUtil {
/**
* @param target
* @param star
* @param end
* @param duration
* @return
*
*
*/
public static ObjectAnimator createFlyFromLtoR(final View target, float star, float end, int duration, TimeInterpolator interpolator) {
//1.
ObjectAnimator anim1 = ObjectAnimator.ofFloat(target, "translationX",
star, end);
anim1.setInterpolator(interpolator);
anim1.setDuration(duration);
return anim1;
}
/**
* @param target
* @return
*
*/
public static AnimationDrawable startAnimationDrawable(ImageView target){
AnimationDrawable animationDrawable = (AnimationDrawable) target.getDrawable();
if(animationDrawable!=null) {
target.setVisibility(View.VISIBLE);
animationDrawable.start();
}
return animationDrawable;
}
/**
* @param target
* @param drawable
*
*/
public static void setAnimationDrawable(ImageView target, AnimationDrawable drawable){
target.setBackground(drawable);
}
/**
* @param target
* @param num
* @return
*
*/
public static ObjectAnimator scaleGiftNum(final TextView target , int num){
PropertyValuesHolder anim4 = PropertyValuesHolder.ofFloat("scaleX",
1.7f, 0.8f,1f);
PropertyValuesHolder anim5 = PropertyValuesHolder.ofFloat("scaleY",
1.7f, 0.8f,1f);
PropertyValuesHolder anim6 = PropertyValuesHolder.ofFloat("alpha",
1.0f, 0f,1f);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(target, anim4, anim5, anim6).setDuration(480);
animator.setRepeatCount(num);
return animator;
}
/**
* @param target
* @param star
* @param end
* @param duration
* @param startDelay
* @return
*
*/
public static ObjectAnimator createFadeAnimator(final View target, float star, float end, int duration, int startDelay){
PropertyValuesHolder translationY = PropertyValuesHolder.ofFloat("translationY", star,end);
PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1.0f,0f);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(target, translationY, alpha);
animator.setStartDelay(startDelay);
animator.setDuration(duration);
return animator;
}
/**
* @param animators
* @return
*
*/
public static AnimatorSet startAnimation(ObjectAnimator animator1, ObjectAnimator animator2, ObjectAnimator animator3, ObjectAnimator animator4, ObjectAnimator animator5){
AnimatorSet animSet = new AnimatorSet();
// animSet.playSequentially(animators);
animSet.play(animator1).before(animator2);
animSet.play(animator3).after(animator2);
animSet.play(animator4).after(animator3);
animSet.play(animator5).after(animator4);
animSet.start();
return animSet;
}
}
모든 애니메이션 효 과 는 속성 애니메이션 으로 이 루어 집 니 다.그 중에서 하나의 애니메이션 뿐만 아니 라 조합 애니메이션 도 있 습 니 다.속성 애니메이션 은 사용 하기에 매우 강력 합 니 다!마지막 으로 MainActivity 의 실현 을 살 펴 보 겠 습 니 다.
public class MainActivity extends AppCompatActivity {
private GiftFrameLayout giftFrameLayout1;
private GiftFrameLayout giftFrameLayout2;
List<GiftSendModel> giftSendModelList = new ArrayList<GiftSendModel>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
giftFrameLayout1 = (GiftFrameLayout) findViewById(R.id.gift_layout1);
giftFrameLayout2 = (GiftFrameLayout) findViewById(R.id.gift_layout2);
findViewById(R.id.action).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
starGiftAnimation(createGiftSendModel());
}
});
}
private GiftSendModel createGiftSendModel(){
return new GiftSendModel((int)(Math.random()*10));
}
private void starGiftAnimation(GiftSendModel model){
if (!giftFrameLayout1.isShowing()) {
sendGiftAnimation(giftFrameLayout1,model);
}else if(!giftFrameLayout2.isShowing()){
sendGiftAnimation(giftFrameLayout2,model);
}else{
giftSendModelList.add(model);
}
}
private void sendGiftAnimation(final GiftFrameLayout view, GiftSendModel model){
view.setModel(model);
AnimatorSet animatorSet = view.startAnimation(model.getGiftCount());
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
synchronized (giftSendModelList) {
if (giftSendModelList.size() > 0) {
view.startAnimation(giftSendModelList.get(giftSendModelList.size() - 1).getGiftCount());
giftSendModelList.remove(giftSendModelList.size() - 1);
}
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
캐 시 영역 에 대한 정책 은 실제 수요 에 따라 맞 춤 형 으로 설정 할 수 있 습 니 다.위 에서 말 한 것 은 편집장 이 소개 한 안 드 로 이 드 개발 모방 객 에 게 선물 효 과 를 보 내 는 것 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 면 메 시 지 를 남 겨 주세요.편집장 은 신속하게 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.