안 드 로 이 드 모방 경 동 첫 페이지 윤방 문자 효과
다음 에 실 현 될 것 은 뒤에 구 르 는 문자(앞 에 있 는 것 은 ImageView 나 TextView 로 이 루어 지면 됩 니 다)입 니 다.실 현 된 효 과 를 보 세 요.
사고의 방향 을 실현 하 다.
위의 그림 은 대략적인 사고 일 뿐 이 고 실현 하려 면 더 많은 세부 사항 을 보완 해 야 한다.다음 에 한 걸음 한 걸음 이 효 과 를 실현 할 것 이다.
1.패 키 징 데이터 소스:그림 에서 볼 수 있 듯 이 윤 방 의 문 자 는 두 부분 으로 나 뉘 는데 이 를 접두사 와 내용 이 라 고 부 릅 니 다.그리고 실제 사용 과정 에서 윤 방 도 를 클릭 하면 페이지 를 넘 어야 합 니 다.그리고 대부분 WebView 여야 합 니 다.클릭 할 때 얻 을 내용 이 바로 링크 라 고 설정 하면 데이터 소스 의 구 조 는 분명 합 니 다.
ADEnity
클래스 를 만 들 고 기본 적 인 방법 을 보완 합 니 다.코드 는 다음 과 같 습 니 다.
public class ADEnity {
private String mFront ; //
private String mBack ; //
private String mUrl ;//
public ADEnity(String mFront, String mBack,String mUrl) {
this.mFront = mFront;
this.mBack = mBack;
this.mUrl = mUrl;
}
public String getmUrl() {
return mUrl;
}
public void setmUrl(String mUrl) {
this.mUrl = mUrl;
}
public String getmFront() {
return mFront;
}
public void setmFront(String mFront) {
this.mFront = mFront;
}
public String getmBack() {
return mBack;
}
public void setmBack(String mBack) {
this.mBack = mBack;
}
}
2.다음은 이 사용자 정의 View 를 맞 추 는 것 입 니 다.먼저 생각 을 정리 하고 구조 도 를 보 세 요.이 사용자 정의 View 를 실현 하 는 모든 매개 변 수 는 위 표 에 열거 되 어 있 습 니 다.대부분의 매개 변 수 는 쉽게 이해 할 수 있 습 니 다.개별 매개 변 수 를 추가 하 는 것 이 필요 합 니 다.예 를 들 어 문자 에 들 어 가 는 세로 좌 표를 초기 화 하 는 지,문자 가 이동 중 에 있 는 지,그 후의 내용 은 상세 하 게 서술 할 것 입 니 다.그림 을 그리 기 전에 기본 적 인 지식 을 알 아야 합 니 다.바로 문 자 를 그 리 는 방법 에 관 한 것 입 니 다.그 안에 처리 해 야 할 세부 사항 이 많 습 니 다.
방법 은 모두 이해 하기 쉽 습 니 다.지정 한 문자열(범 위 를 지정 할 수 있 습 니 다)을 그 리 는 것 은 좌표
( x , y )
에 있 습 니 다.그러나 그 중의x,y
은 우리 가 이해 하 는 것 이 아니 라 문자 왼쪽 상단 의 좌표 점 입 니 다.그 중의 x 좌 표 는Paint
의 속성 에 따라 변 경 될 수 있 습 니 다.기본 적 인 x 는 문자 의 왼쪽 좌표 입 니 다.만약Paint
에 설정 되 어 있다 면paint.setTextAlign(Paint.Align.CENTER)
.바로 문자 의 중심 위치 입 니 다.Y
좌 표 는 문자baseline
의y
좌표 입 니 다.문 자 를 그 리 는 baseline:그림 으로 얘 기해 주세요.
그림 에서 파란색 선 은 바로
baseline
이다.그 가 상단 좌표 도 아 닌 밑부분 좌표 임 을 알 수 있다.그러면 우리 가 문 자 를 그 릴 때 문 자 를 한가운데 에 그 리 려 고 하 는 것 이 분명 하 다.이때paint.getTextBound()
방법getTextBounds(String text, int start, int end, Rect bounds)
을 도입 하여Rect
대상 에 게 전달 하고 이 방법 을 사용 하면 이 rect 대상 을 채 울 것 이다.채 워 진 내용 은 그 려 진 텍스트 가baseline
의 오프셋 좌표 에 비해 이 Rect 에baseline
의 좌 표를 더 해서 그 려 진 것 입 니 다.그러나 사실 그의 수 치 는
(2,-25,76,3)
일 뿐 baseline 의 위치 에 비해 그림 을 그 리 는 것 이 이해 하기 쉽다.텍스트 를 중간 에 그 리 려 면 실제 baseline 의 좌 표를 구성 요소 의 중심 에 텍스트 중심,즉 그림 속 상자 의 중간 좌 표를 baseline 의 오프셋 값 에 비해 그 려 야 합 니 다.>그러면 텍스트 를 중간 에 그 리 려 면 baseline 의 좌 표를 실제 그 리 는 것 은 그룹 부품 의 중심 이 어야 합 니 다.여기에 텍스트 중심(즉 그림 속 상자 의 중간 좌표)을 baseline 의 오프셋 값 에 비해 그 려 야 합 니 다.
이 그림 은 실제 텍스트 를 그 리 는 좌표 와 구성 요소 중심 좌표 의 관 계 를 잘 이해 할 수 있 을 것 입 니 다.오프셋 값 에 대한 계산 은 일반적인 기하학 적 계산 방법 에 따라 구성 요소 의 중심 좌표+오프셋 값 의 절대 값=baseline 좌표(즉,실제 그 리 는 좌표)여야 합 니 다.그러나 상자 의 좌표 값 은 모두 baseline 에 비해 계산 되 기 때문에 top 은 마이너스 이 고 botton 은 플러스 입 니 다.그러면 이 오프셋 값 은(top+bottom)/2 로 직접 표시 할 수 있 습 니 다.못 알 아 본 학생 은 약 도 를 그 릴 수 있 습 니 다.top=-25,bottom=3 으로 계산 하여 결과 가 일치 하 는 지 확인 할 수 있 습 니 다.
위의 이 해 를 통 해 우 리 는 문 자 를 정확하게 그 리 는 방법 도 확정 되 었 다.
구성 요소 의 높이 int mHeight,텍스트 외곽 상자 Rect bound 를 획득 한 경우
그림%1 개의 캡 션 을 편 집 했 습 니 다.
mHeight / 2 - (bound.top + bound.bottom) / 2
// mY
//
//mheight /2 = mY + (bound.top + bound.bottom) / 2 ;
텍스트 를 최고점 으로 스크롤
mY == 0 - bound.bottom
// mY ,
//
//mY + bound.bottom = 0 ;
텍스트 가 가장 낮은 곳 으로 스크롤 되 었 습 니 다.마침 구성 요소 에서 꺼 졌 습 니 다.
mY = mHeight - indexBound.top;
// mY ,
//
//mY + bound.top = mHeight ;
문자 와 경계 상황 을 정확하게 그 리 는 좌 표를 알 게 되 었 습 니 다.다음은 문 자 를 그 리 는 절차 입 니 다.우선 데 이 터 를 초기 화하 고 기본 값 을 설정 합 니 다.
//
private void init() {
mDuration = 500;
mInterval = 1000;
mIndex = 0;
mPaintFront = new Paint();
mPaintFront.setAntiAlias(true);
mPaintFront.setDither(true);
mPaintFront.setTextSize(30);
mPaintBack = new Paint();
mPaintBack.setAntiAlias(true);
mPaintBack.setDither(true);
mPaintBack.setTextSize(30);
}
앞의 서술 에서 우 리 는 처음에 들 어 갔 을 때 문 자 는 구성 요소 의 아래쪽 에 있어 야 한 다 는 것 을 알 고 있 습 니 다.그러나 이 값 은 구성 요소 의 높이 와 현재 표 시 된 문 자 를 가 져 와 서 판단 해 야 하기 때문에 onDraw 에 넣 어서 이 값 을 초기 화 해 야 합 니 다.따라서 앞의 속성 이 초기 화 되 었 는 지 여 부 를 판단 하고 mY==0 이 초기 화 되 지 않 았 을 때 mY 에 값 을 부여 해 야 합 니 다.다음은 온 드 로 내 처리.
현재 데이터 가 져 오기
//
ADEnity model = mTexts.get(mIndex);
String font = model.getmFront();
String back = model.getmBack();
//
Rect indexBound = new Rect();
mPaintFront.getTextBounds(font, 0, font.length(), indexBound);
//
Rect contentBound = new Rect();
mPaintBack.getTextBounds(back, 0, back.length(), contentBound);
mY 초기 화
if (mY == 0 && hasInit == false) {
mY = getMeasuredHeight() - indexBound.top;
hasInit = true;
}
경계 상황 처리/
/
if (mY == 0 - indexBound.bottom) {
Log.i(TAG, "onDraw: " + getMeasuredHeight());
mY = getMeasuredHeight() - indexBound.top;//
mIndex++;//
}
//
if (mY == getMeasuredHeight() / 2 - (indexBound.top + indexBound.bottom) / 2) {
isMove = false;//
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
postInvalidate();//
isMove = true;// true
}
}, mInterval);//
}
mY -= 1;// ,
//
if (mIndex == mTexts.size()) {
mIndex = 0;
}
// ,
// , , 1
if (isMove) {
postInvalidateDelayed(mDuration / getMeasuredHeight());
}
,
public interface onClickLitener {
public void onClick(String mUrl);
}
private onClickLitener onClickLitener;
public void setOnClickLitener(TextViewAd.onClickLitener onClickLitener) {
this.onClickLitener = onClickLitener;
}
// onTouchEvent , true,
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// ,
if (onClickLitener != null) {
onClickLitener.onClick(mTexts.get(mIndex).getmUrl());
}
break;
}
return true;
}
//
public void setmTexts(List mTexts) {
this.mTexts = mTexts;
}
//
public void setmInterval(int mInterval) {
this.mInterval = mInterval;
}
//
public void setmDuration(int mDuration) {
this.mDuration = mDuration;
}
//
public void setFrontColor(int mFrontColor) {
mPaintFront.setColor(mFrontColor);
}
//
public void setBackColor(int mBackColor) {
mPaintBack.setColor(mBackColor);
}
attrs.xml , , copy View xml copy , as , .( ).
ADTextView ,
package com.qiyuan.jindongshangcheng.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;
import com.qiyuan.jindongshangcheng.enity.ADEnity;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
/**
* Created by huanghaojie on 2016/9/30.
*/
public class TextViewAd extends TextView {
private int mDuration; //
private int mInterval; //
private List<ADEnity> mTexts; //
private int mY = 0; // Y
private int mIndex = 0; //
private Paint mPaintBack; //
private Paint mPaintFront; //
private boolean isMove = true; //
private String TAG = "ADTextView";
private boolean hasInit = false;//
public interface onClickLitener {
public void onClick(String mUrl);
}
private onClickLitener onClickLitener;
public void setOnClickLitener(TextViewAd.onClickLitener onClickLitener) {
this.onClickLitener = onClickLitener;
}
public TextViewAd(Context context) {
this(context, null);
}
public TextViewAd(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
// onTouchEvent , true,
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// ,
if (onClickLitener != null) {
onClickLitener.onClick(mTexts.get(mIndex).getmUrl());
}
break;
}
return true;
}
//
public void setmTexts(List mTexts) {
this.mTexts = mTexts;
}
//
public void setmInterval(int mInterval) {
this.mInterval = mInterval;
}
//
public void setmDuration(int mDuration) {
this.mDuration = mDuration;
}
//
public void setFrontColor(int mFrontColor) {
mPaintFront.setColor(mFrontColor);
}
//
public void setBackColor(int mBackColor) {
mPaintBack.setColor(mBackColor);
}
//
private void init() {
mDuration = 500;
mInterval = 1000;
mIndex = 0;
mPaintFront = new Paint();
mPaintFront.setAntiAlias(true);
mPaintFront.setDither(true);
mPaintFront.setTextSize(30);
mPaintBack = new Paint();
mPaintBack.setAntiAlias(true);
mPaintBack.setDither(true);
mPaintBack.setTextSize(30);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Log.i(TAG, "onSizeChanged: " + h);
}
@Override
protected void onDraw(Canvas canvas) {
if (mTexts != null) {
Log.i(TAG, "onDraw: " + mY);
//
ADEnity model = mTexts.get(mIndex);
String font = model.getmFront();
String back = model.getmBack();
//
Rect indexBound = new Rect();
mPaintFront.getTextBounds(font, 0, font.length(), indexBound);
//
Rect contentBound = new Rect();
mPaintBack.getTextBounds(back, 0, back.length(), contentBound);
// , ,
// onDraw , , mY==0 mY .
if (mY == 0 && hasInit == false) {
mY = getMeasuredHeight() - indexBound.top;
hasInit = true;
}
//
if (mY == 0 - indexBound.bottom) {
Log.i(TAG, "onDraw: " + getMeasuredHeight());
mY = getMeasuredHeight() - indexBound.top;//
mIndex++;//
}
canvas.drawText(back, 0, back.length(), (indexBound.right - indexBound.left) + 20, mY, mPaintBack);
canvas.drawText(font, 0, font.length(), 10, mY, mPaintFront);
//
if (mY == getMeasuredHeight() / 2 - (indexBound.top + indexBound.bottom) / 2) {
isMove = false;//
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
postInvalidate();//
isMove = true;// true
}
}, mInterval);//
}
//
mY -= 1;// ,
//
if (mIndex == mTexts.size()) {
mIndex = 0;
}
// ,
// , , 1
if (isMove) {
postInvalidateDelayed(mDuration / getMeasuredHeight());
}
}
}
}
?
1, xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.qiyuan.jindongshangcheng.view.TextViewAd
android:id="@+id/textad"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
2. MainActivity
/**
* Created by huanghaojie on 2016/9/30.
*/
public class MainActivity extends Activity {
private TextViewAd textViewAd;
private List<ADEnity> mList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
textViewAd = (TextViewAd) findViewById(R.id.textad);
mList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
ADEnity adEnity = new ADEnity(" " + i, " " + i, "http://www.baidu.com"+i);
mList.add(adEnity);
}
textViewAd.setmTexts(mList);
textViewAd.setFrontColor(Color.RED);
textViewAd.setBackColor(Color.BLUE);
textViewAd.setmDuration(1000);
textViewAd.setmInterval(1000);
textViewAd.setOnClickLitener(new TextViewAd.onClickLitener() {
@Override
public void onClick(String mUrl) {
Toast.makeText(MainActivity.this," "+mUrl,Toast.LENGTH_LONG).show();
}
});
}
}
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 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에 따라 라이센스가 부여됩니다.