안 드 로 이 드 프리미엄 소니 스크롤 앨범
우선 효과 그림:
주요 제스처 동작 은 다음 과 같 습 니 다.
1.위/아래 만 속 이동,한 장의 그림 을 위/아래로 미 끄 러 뜨 릴 수 있 습 니 다.
2.위/아래 빠르게 읽 고 이동 하면 미끄럼 속도 에 따라 위/아래 여러 장의 그림 이 미 끄 러 집 니 다.
3.클릭 하면 시스템 갤러리 에 이 그림 을 보 여 달라 고 요청 합 니 다.
이 작은 위 젯 의 주요 장점 은 화면 안의 작은 범위 에서 좋 은 그림 선택/위 젯 을 제공 합 니 다.특히 그림 을 전환 할 때 애니메이션 감각 을 멀리 하고 호감 을 가 집 니 다.
코드 분석
처음에 이 작은 부품 을 생각 할 때 여러 개의 ImageView 를 중첩 하여 실현 하 는 효과 라 고 생각 했다.예 를 들 어 구 글 원생 의 이 부품 은 여러 개의 ImageView 를 중첩 하여 형 성 된 것 이지 만 효 과 는 이것 보다 훨씬 못 하 다.하지만 여러 이미지 뷰 를 통 해 중첩 하면 이렇게 원활 하지 않 고 성능 도 좋 지 않 을 것 같다.이 효과 자체 도 비교적 규칙 적 이 므 로 하나의 View 를 통 해 실현 하여 더욱 좋 은 성능 을 얻 을 수 있 을 것 이다.그래서 View Hierarchy 분석 을 통 해 소니 는 역시 하나의 View 를 통 해 이 루어 졌 기 때문에 다음 과 같은 방식 으로 이 작은 부품 을 분석 했다.
코드 는 주로 세 부분 으로 구성 된다.
•RollImageView:실제 View
•CellCalculator:모든 그림 의 그리 기 영역 과 투명 도 를 실시 간 으로 계산 합 니 다.이것 은 이 작은 부품 의 핵심 부품 입 니 다.인터페이스 정 의 는 다음 과 같 습 니 다.
/**
* get all rects for drawing image
* @return
*/
public Cell[] getCells();
/**
*
* @param distance the motion distance during the period from ACTION_DOWN to this moment
* @return 0 means no roll, positive number means roll forward and negative means roll backward
*/
public int setStatus(float distance);
/**
* set the dimen of view
* @param widht
* @param height
*/
public void setDimen(int widht, int height);
/**
* set to the status for static
*/
public void setStatic();
•ImageLoader:그림 을 불 러 오고 Bitmap 를 제공 하여 RollImageView 에 그립 니 다.인터페이스 정 의 는 다음 과 같 습 니 다.
/**
* the images shown roll forward
*/
public void rollForward();
/**
* the images shown roll backward
*/
public void rollBackward();
/**
* get bitmaps
* @return
*/
public Bitmap[] getBitmap();
/**
* use invalidate to invalidate the view
* @param invalidate
*/
public void setInvalidate(RollImageView.InvalidateView invalidate);
/**
* set the dimen of view
* @param width
* @param height
*/
public void setDimen(int width, int height);
/**
* the image path to be show
* @param paths
*/
public void setImagePaths(List<String> paths);
/**
* get large bitmap while static
*/
public void loadCurrentLargeBitmap();
다음은 각 부분의 핵심 코드 를 분석 하 겠 습 니 다. RollImageView
View 의 주요 직책 은 draw 각 bitmap 와 사용자 의 제스처 동작 에 응답 하 는 것 으로 상대 적 으로 간단 합 니 다.
그리 기 부분 은 ImageLoader 에서 얻 은 각 Bitmap 를 CellCalculater 에서 얻 은 그리 기 영역 과 투명도 에 따라 화면 에 그 리 는 것 입 니 다.현재 이 코드 는 비교적 간단 합 니 다.서로 다른 사이즈 의 그림 을 고려 하지 않 고 더욱 조 화 롭 게 표시 해 야 합 니 다.예 를 들 어 ImageView.Scale Type 에서 정의 한 디 스 플레이 방식 입 니 다.
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Bitmap[] bitmaps = mImageLoader.getBitmap();
Cell[] cells = mCellCalculator.getCells(); // Image
canvas.translate(getWidth() / 2, 0);
for (int i = SHOW_CNT - 1; i >= 0; i--) { // Image
Bitmap bitmap = bitmaps[i];
Cell cell = cells[i];
if (bitmap != null && !bitmap.isRecycled()) {
mPaint.setAlpha(cell.getAlpha());
LOG("ondraw " + i + bitmap.getWidth() + " " + cell.getRectF() + " alpha " + cell.getAlpha());
canvas.drawBitmap(bitmap, null, cell.getRectF(), mPaint);
}
}
}
제스처 부분 은 GestureListener 를 사 용 했 습 니 다.주요 코드 는 다음 과 같 습 니 다.
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getPointerCount() > 1) {
return false;
}
mGestureDetector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_UP: // Fling ,
if(!mIsFling){
if(mRollResult == CellCalculator.ROLL_FORWARD){
mImageLoader.rollForward();
} else if (mRollResult == CellCalculator.ROLL_BACKWARD && !mScrollRollBack){
mImageLoader.rollBackward();
}
LOG("OnGestureListener ACTION_UP setstatic " );
mCellCalculator.setStatic();
mImageLoader.loadCurrentLargeBitmap();
}
break;
default:
break;
}
return true;
}
//
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
mScrollDistance += distanceY;
if(mScrollDistance > 0 && !mScrollRollBack){
mImageLoader.rollBackward();
mScrollRollBack = true;
} else if(mScrollDistance < 0 && mScrollRollBack){
mImageLoader.rollForward();
mScrollRollBack = false;
}
LOG("OnGestureListener onScroll " + distanceY + " all" + mScrollDistance);
mRollResult = mCellCalculator.setStatus(-mScrollDistance);
invalidate();
return true;
}
//
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (Math.abs(velocityY) > MIN_FLING) {
LOG("OnGestureListener onFling " + velocityY);
if (mExecutorService == null) {
mExecutorService = Executors.newSingleThreadExecutor();
}
mIsFling = true;
mExecutorService.submit(new FlingTask(velocityY));
}
return true;
}
// Images
private class FlingTask implements Runnable {
float mVelocity;
float mViewHeight;
int mSleepTime;
boolean mRollBackward;
FlingTask(float velocity) {
mRollBackward = velocity < 0 ? true : false;
mVelocity = Math.abs(velocity / 4);
mViewHeight = RollImageView.this.getHeight() / 2;
mSleepTime = (int)(4000 / Math.abs(velocity) * 100); //the slower velocity of fling, the longer interval for roll
}
@Override
public void run() {
int i = 0;
try{
while (mVelocity > mViewHeight) {
mCellCalculator.setStatus(mRollBackward ? -mViewHeight : mViewHeight);
mHandler.sendEmptyMessage(MSG_INVALATE);
//determines the count of roll. The using of mViewHeight has no strictly logical
mVelocity -= mViewHeight;
if (((i++) & 1) == 0) { //roll forward once for every two setStatus
if(mRollBackward){
mImageLoader.rollBackward();
}else {
mImageLoader.rollForward();
}
}
Thread.sleep(mSleepTime);
}
mCellCalculator.setStatic();
mImageLoader.loadCurrentLargeBitmap();
mHandler.sendEmptyMessage(MSG_INVALATE);
} catch(Exception e){
} finally{
}
}
}
셀 계산기 분석먼저 앞으로 이동/뒤로 이동 하 는 개념 을 천명 하 다.표시 할 그림 경 로 는 하나의 List 로 저장 되 어 있 습 니 다.맨 앞 에 표 시 된 그림 의 색인 이 index 라 고 가정 하면 현재 표 시 된 그림 은[index,index+3]이 고 앞 으로 는 index 플러스 1 을 표시 하 며 뒤로 는 index 감 1 을 표시 합 니 다.
CellCalculator 의 계산 상황 은 주로 사용자 가 손짓 을 통 해 그림 을 앞으로 이동 하거나 뒤로 이동 해 야 한 다 는 의 도 를 나 타 냈 다.View 에서 얻 을 수 있 는 것 은 제스처 로 이동 하 는 거리 이기 때문에 CellCalculater 에서 들 어 오 는 이동 거 리 를 처리 하고 이동 결 과 를 출력 해 야 합 니 다.나의 실현 에서 이동 거리 가 그림 높이 의 절반 을 초과 할 때 표 시 된 그림 은 한 자 리 를 이동 해 야 한 다 는 것 을 나타 낸다.그렇지 않 으 면 제스처 조작 이 끝 날 때 static 상태 로 설정 된다.주요 코드 는 다음 과 같 습 니 다.
public DefaultCellCalculator(int showCnt){
mCnt = showCnt;
mCells = new Cell[mCnt];
mAlphas = new float[mCnt];
STATIC_ALPHA = new int[mCnt];
STATIC_ALPHA[mCnt - 1] = 0; // 0
int alphaUnit = (255 - FIRST_ALPHA) / (mCnt - 2);
for(int i = mCnt - 2; i >= 0; i--){ //
STATIC_ALPHA[i] = FIRST_ALPHA + (mCnt - 2 - i) * alphaUnit;
}
}
@Override
public Cell[] getCells() {
return mCells;
}
// ,distance , /
@Override
public int setStatus(float distance) {
if(distance > 0){
return calculateForward(distance);
} else if(distance < 0){
return calculateBackward(distance);
} else{
initCells();
}
return 0;
}
// RollImageView ,
@Override
public void setDimen(int widht, int height) {
mViewWidth = widht;
mViewHeight = height;
mWidhtIndent = (int)(WIDHT_INDENT * mViewWidth);
mWidths = new int[mCnt];
for(int i = 0; i < mCnt; i++){
mWidths[i] = mViewWidth - i * mWidhtIndent;
}
// 。
// , , , mcnt-1
mImageHeight = mViewHeight - (mCnt - 1) * HEIGHT_INDENT;
LOG("mImageHeight " + mImageHeight);
initCells();
}
// ,
@Override
public void setStatic() {
initCells();
}
//
private int calculateForward(float status){
float scale = status / mImageHeight;
LOG("scale " + scale + " mImageHeight " + mImageHeight + " status " + status);
for(int i = 1; i < mCnt; i++){
mCells[i].setWidth(interpolate(scale * 3, mWidths[i], mWidths[i - 1])); // *3 ,
mCells[i].moveVertical(interpolate(scale * 10, 0, HEIGHT_INDENT)); //*10 ,
mCells[i].setAlpha((int)interpolate(scale, STATIC_ALPHA[i], STATIC_ALPHA[i - 1]));
}
mCells[0].moveVertical(status);
mCells[0].setAlpha((int)interpolate(scale, 255, 0));
if(status >= mImageHeight / 3){
return ROLL_FORWARD;
} else {
return 0;
}
}
//
private int calculateBackward(float status){
float scale = Math.abs(status / mImageHeight);
for(int i = 1; i < mCnt; i++){
mCells[i].setWidth(interpolate(scale, mWidths[i - 1], mWidths[i]));
mCells[i].moveVertical(-scale * HEIGHT_INDENT);
mCells[i].setAlpha((int)interpolate(scale, STATIC_ALPHA[i - 1], STATIC_ALPHA[i]));
}
mCells[0].resetRect();
mCells[0].setWidth(mWidths[0]);
mCells[0].setHeight(mImageHeight);
mCells[0].moveVertical(mImageHeight + status);
mCells[0].setAlpha((int)interpolate(scale, 0, 255));
if(-status >= mImageHeight / 3){
return ROLL_BACKWARD;
} else {
return 0;
}
}
/**
* status without move
*/
private void initCells(){
int top = -HEIGHT_INDENT;
for(int i = 0; i < mCnt; i++){
RectF rectF = new RectF(0,0,0,0);
rectF.top = top + (mCnt - 1 - i) * HEIGHT_INDENT;
rectF.bottom = rectF.top + mImageHeight;
mCells[i] = new Cell(rectF, STATIC_ALPHA[i]);
mCells[i].setWidth(mWidths[i]);
}
}
//
private float interpolate(float scale, float start, float end){
if(scale > 1){
scale = 1;
}
return start + scale * (end - start);
}
ImageLoader 분석ImageLoader 는 사실 비교적 간단 하 다.주로 다음 과 같은 두 가지 가 있다.
•제스처 동작 에 응답 하여 앞으로/뒤로 이동 할 때 Bitmap 요청 처리
•제스처 가 아직 조작 되 고 있 을 때 작은 그림 을 불 러 오고 제스처 작업 이 끝 난 후에 큰 그림 을 불 러 와 야 합 니 다.천천히 이동 할 때 만 선명 하 게 표시 되 고 빠르게 이동 할 때 작은 그림 을 표시 하면 되 기 때문에 현재 index 와 앞으로 그림 을 불 러 오 면 됩 니 다.
// index
@Override
public void loadCurrentLargeBitmap() {
for(int i = mCurrentIndex - 1; i < mCurrentIndex + 2; i++){
if(i >= 0 && i < mImagesCnt - 1){
mBitmapCache.getLargeBitmap(mAllImagePaths[i]);
}
}
}
//index
@Override
public void rollForward() {
LOG("rollForward");
mCurrentIndex++;
if(mCurrentIndex > mImagesCnt - 1){
mCurrentIndex = mImagesCnt - 1;
}
setCurrentPaths();
}
//index
@Override
public void rollBackward() {
LOG("rollBackward");
mCurrentIndex--;
if(mCurrentIndex < 0){
mCurrentIndex = 0;
}
setCurrentPaths();
}
@Override
public Bitmap[] getBitmap() {
if(mCurrentPaths != null){
LOG("getBitmap paths nut null");
for(int i = mCurrentIndex, j = 0; j < mShowCnt; j++, i++){
if(i >= 0 && i < mImagesCnt){
mCurrentBitmaps[j] = mBitmapCache.getBimap(mAllImagePaths[i]);
} else{
mCurrentBitmaps[j] = mBitmapCache.getBimap(NO_PATH);
}
}
}
return mCurrentBitmaps;
}
마지막 으로 모든 소스 코드:https://github.com/willhua/RollImage이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 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에 따라 라이센스가 부여됩니다.