Android,위 챗 사 이 드 슬라이딩 페이지 닫 기 효과 구현
그래서 저 는 사용자 정의 View 없 이도 실현 할 수 있 는 다른 방법 을 실 현 했 습 니 다.그 하위 클래스 는 이 를 계승 하면 옆으로 미 끄 러 지 는 기능 을 가 질 수 있 습 니 다.
한 마디 만 해도 이 방법 은 5.0 이상 의 핸드폰 에 만 효과 가 있 습 니 다(어차피 위 챗 도 5.0 에서 만 사용 할 수 있 습 니 다).5.0 이하 의 것 은 무시 하 세 요!!
의 원리
모든 Activity 에 밑 에 있 는 View,즉 rootView 가 있 습 니 다.xml 레이아웃 을 불 러 올 때 시스템 은 자동 으로 이 rootView 를 생 성 합 니 다.이것 은 View 이기 때문에 일정한 코드 를 통 해 이 레이아웃 을 마음대로 이동 할 수 있 음 을 의미 합 니 다.
다음 코드 에서 보 듯 이 간단 한 몇 줄 코드 만 있 으 면 레이아웃 의 이동 을 실현 할 수 있 습 니 다.
public class SlideActivity extends AppCompatActivity {
View mRootView;
private GestureDetector mDetector;
private int mWindowWidth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
mRootView = getWindow().getDecorView();
mRootView.setBackgroundColor(Color.BLUE);
mDetector = new GestureDetector(this, new GestureListener());
mWindowWidth = getWindow().getWindowManager().getDefaultDisplay().getWidth();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mDetector.onTouchEvent(event);
}
/**
*
*/
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (e1 != null) {
handlerCurrentActivityScroll(e2);
}
return super.onScroll(e1, e2, distanceX, distanceY);
}
/**
*
*/
private void handlerCurrentActivityScroll(MotionEvent e2) {
mRootView.setTranslationX(e2.getX());
if (e2.getX() > mWindowWidth - 20) {
finish();
}
}
}
}
이게 저희 효과 예요.활동 연동
이 차 이 는 여전히 매우 크다.가장 뚜렷 한 점 은 우리 가 이동 할 때 지난 층 의 Activity 가 뜻밖에도 연동 되 지 않 았 다 는 것 이다.
이 문 제 를 해결 하 는 방법 도 간단 합 니 다.그림 에서 보 듯 이 Activity 를 시작 할 때마다 시스템 은 Activity 를 하나의 스 택 에 넣 습 니 다.스 택 의 작업 원 리 를 통 해 알 수 있 듯 이 APP 안의 Activity 는 한 층 씩 덮 여 있 습 니 다.위의 그림 과 같 습 니 다.이 를 위해 하나의 Activity 를 시작 할 때마다 현재 Activity 를 하나의 List 에 저장 할 수 있 습 니 다.그러면 우 리 는 현재 Activity 에서 이전 Activity 를 꺼 내 조작 할 수 있 습 니 다.
따라서 새로운 Activity 에 들 어 갈 때 onCreate 방법 에서 현재 Activity 를 목록 에 불 러 오고 종료 할 때 finish 의 재 부팅 방법 에서 현재 Activity 를 목록 에서 제거 합 니 다.
조심해!!!미 끄 러 질 때 는 Activity 에 ListView 와 같은 미끄럼 컨트롤 이 있 을 수 있 음 을 고려 해 야 하기 때문에 이벤트 에 대한 배포 제어 가 필요 합 니 다.
코드 는 다음 과 같다.
/**
* Created by yuyu on 2015/10/29.
*/
public class TestActivity extends AppCompatActivity {
View mRootView;
private GestureDetector mGestureDetector;
private static List<TestActivity> mActivitys = new ArrayList<>();
/**
*
*/
private float mWindowWidth;
private TestActivity mBeforeActivity;
/**
* Activity
*/
private float mOffsetX;
/**
*
*/
private float mOutsideWidth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
/**
* Activity
*/
mActivitys.add(this);
initScrollBack();
}
/**
*
*/
private void initScrollBack() {
mWindowWidth = getWindowManager().getDefaultDisplay().getWidth();
mOutsideWidth = -mWindowWidth / 4;
mOffsetX = mOutsideWidth;
mGestureDetector = new GestureDetector(this, new GestureListener());
mRootView = getWindow().getDecorView();
mRootView.setBackgroundColor(Color.BLUE);
}
/**
* ,
*/
@Override
public boolean dispatchTouchEvent(@NonNull MotionEvent ev) {
if (ev.getX() < mWindowWidth / 10) {
if (mActivitys.size() > 1) {
mBeforeActivity = mActivitys.get(mActivitys.size() - 2);
beforeActivityTranslationX(mOutsideWidth);
}
return onTouchEvent(ev);
}
return super.dispatchTouchEvent(ev);
}
@Override
public void finish() {
mActivitys.remove(this);
if (mOffsetX < 0.0001 || mOffsetX > 0.0001) {
beforeActivityTranslationX(0);
}
super.finish();
}
public void onClick(View view) {
Intent intent = new Intent(this, Activity5.class);
startActivity(intent);
}
public View getRootView() {
return mRootView;
}
/**
* Activity
*/
private void beforeActivityTranslationX(float translationX) {
if (mBeforeActivity != null) {
mBeforeActivity.getRootView().setTranslationX(translationX);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
/**
*
*/
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (e1 != null) {
handlerCurrentActivityScroll(e2);
handleBeforeActivityScroll(e2, distanceX);
}
return super.onScroll(e1, e2, distanceX, distanceY);
}
/**
*
*/
private void handlerCurrentActivityScroll(MotionEvent e2) {
mRootView.setTranslationX(e2.getX());
if (e2.getX() > mWindowWidth - 20) {
finish();
}
}
/**
*
*/
private void handleBeforeActivityScroll(MotionEvent e2, float distanceX) {
if (mBeforeActivity != null) {
mOffsetX = distanceX < 0 ? mOffsetX + Math.abs(distanceX) / 4 : mOffsetX - Math.abs(distanceX) / 4;
if (mOffsetX > 0.0001) {
mOffsetX = 0f;
}
mBeforeActivity.getRootView().setTranslationX(mOffsetX);
}
}
}
}
이것 은 연동 후의 효과 도 이다.지금 은 약간의 효과 가 있 는 셈 이지 만,위 챗 과 의 차 이 는 여전히 매우 크다.이어서 우 리 는 자동 미끄럼 처 리 를 시작 해 야 한다.
자동 미끄럼
이것 은 더 말 할 필요 가 없다.이것 은 주로 속성 애니메이션 을 이용 하여 이동 하 는 것 이다.
다음은 완전한 코드 입 니 다.
public class SlideActivity extends AppCompatActivity {
private static final String TAG = "SlideActivity";
private static List<SlideActivity> mActivitys = new ArrayList<>();
/**
*
*/
private GestureDetector mGestureDetector;
private View mRootView;
private boolean isScroll = false;
/**
*
*/
private float mWindowWidth;
private SlideActivity mBeforeActivity;
/**
* Activity
*/
private float mOffsetX;
/**
*
*/
private float mOutsideWidth;
private boolean canScrollBack = true;
private boolean canScroll = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
getWindow().setEnterTransition(new Slide(Gravity.RIGHT));
super.onCreate(savedInstanceState);
/**
* Activity
*/
mActivitys.add(this);
initScrollBack();
}
@Override
public void startActivity(Intent intent) {
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
}
/**
*
*/
private void initScrollBack() {
mWindowWidth = getWindowManager().getDefaultDisplay().getWidth();
mOutsideWidth = -mWindowWidth / 4;
mOffsetX = mOutsideWidth;
mGestureDetector = new GestureDetector(this, new GestureListener());
mRootView = getWindow().getDecorView();
}
/**
* Activity
*/
private void beforeActivityTranslationX(float translationX) {
if (mBeforeActivity != null) {
mBeforeActivity.getRootView().setTranslationX(translationX);
}
}
/**
*
*
* @param canScrollBack true
*/
protected void setCanScrollBack(boolean canScrollBack) {
this.canScrollBack = canScrollBack;
}
public View getRootView() {
return mRootView;
}
@Override
public void finish() {
mActivitys.remove(this);
if (mOffsetX < 0.0001 || mOffsetX > 0.0001) {
beforeActivityTranslationX(0);
}
super.finish();
}
/**
*
*/
@Override
public boolean dispatchTouchEvent(@NonNull MotionEvent ev) {
if (canScrollBack && ev.getX() < mWindowWidth / 10) {
if (mActivitys.size() > 1) {
mBeforeActivity = mActivitys.get(mActivitys.size() - 2);
beforeActivityTranslationX(mOutsideWidth);
}
canScroll = true;
return onTouchEvent(ev);
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (canScrollBack && canScroll) {
if (event.getAction() == MotionEvent.ACTION_UP && isScroll) {
isScroll = false;
canScroll = false;
// Activity
if (event.getX() > mWindowWidth / 2) {
if (mBeforeActivity != null) {
ObjectAnimator.ofFloat(mBeforeActivity.getRootView(), "translationX", mOffsetX, 0).setDuration(500).start();
}
ObjectAnimator moveIn = ObjectAnimator.ofFloat(mRootView, "translationX", event.getX(), mWindowWidth);
moveIn.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
finish();
}
});
moveIn.setDuration(500).start();
//
} else if (event.getX() < mWindowWidth / 2) {
ObjectAnimator.ofFloat(mRootView, "translationX", event.getX(), 0).setDuration(500).start();
if (mBeforeActivity != null) {
ObjectAnimator.ofFloat(mBeforeActivity.getRootView(), "translationX", mOffsetX, mOutsideWidth).setDuration(500).start();
}
mOffsetX = mOutsideWidth;
}
} else {
mGestureDetector.onTouchEvent(event);
}
}
return true;
}
/**
*
*/
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (e1 != null) {
handlerCurrentActivityScroll(e2);
handleBeforeActivityScroll(e2, distanceX);
}
return super.onScroll(e1, e2, distanceX, distanceY);
}
/**
*
*/
private void handlerCurrentActivityScroll(MotionEvent e2) {
isScroll = true;
mRootView.setTranslationX(e2.getX());
if (e2.getX() > mWindowWidth - 20) {
finish();
}
}
/**
*
*/
private void handleBeforeActivityScroll(MotionEvent e2, float distanceX) {
if (mBeforeActivity != null) {
mOffsetX = distanceX < 0 ? mOffsetX + Math.abs(distanceX) / 4 : mOffsetX - Math.abs(distanceX) / 4;
if (mOffsetX > 0.0001) {
mOffsetX = 0f;
}
mBeforeActivity.getRootView().setTranslationX(mOffsetX);
}
}
}
}
저희 의 최종 효과 도 입 니 다.이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.