編輯:關於Android編程
最近在做通訊錄看到360通訊錄和索尼系統內置通訊錄有這個效果,就是點擊聯系人列表的A-Z側邊欄時,A-Z欄的被觸摸處會扭曲成半圓,半圓可以隨著手指在A-Z移動。索尼手機的比較高級,扭曲和恢復的過程有阻尼效果,360的沒有任何效果就一伸一縮。所本人實現了個360效果一摸一樣的,A-Z側邊欄。
一.實現原理講解:
我們知道正常的A-Z欄每個字母的坐標的Y值應該是一樣的(起碼差不多一樣),所以繪制出來的時候三豎直的。因此我只要按照如下步驟,就可以實現圖中的效果:
1.當A-Z欄被觸摸時,通過setLayoutParams()方法改變他的寬度(本列為100dp)使得它有足夠的空間顯示繪制的半圓效果(本例正常狀態的寬度為30dp)。這裡需要注意的是,當setLayoutParams()調用後,我們要保持A-Z欄在屏幕的位置不變,就要根據情況重新計算每個字母的坐標。
2.在寬度調好之後,要獲取當前被觸摸的字母的在A-Z在豎直線上的坐標(既途中M水平線和A-Z豎直線的交點)作為扭曲半圓的圓心,如圖當前被觸摸的為M,那麼圓心在A-Z欄沒被扭曲時M的位置。
3.在確定好圓心之後,我們要求半徑。如圖,我們把7個字母繪制在了半圓上,那麼A-Z欄豎直線的空白處長度就為,半圓的直徑。可以輕易的看出直徑是7個字母的長度,我們可以很容易的計算出每個字母的高度。再次我們獲得了半徑的值
4.求這七個字母的坐標。首先, 來理一理Android的角度問題,圖中Q所在角度為90,M為180,I為270;得出每個字母的偏移角度分別為:J -- 247.5, K -- 225, L --202.5,
M -- 180, N -- 157.5, O -- 135, P -- 112.5。
在獲得半徑radius, 角度arc ,和圓心坐標O(centerX, centerY)後通過如下公式就可以球道這七個字母的坐標
x = (float) (centerX + radius * Math.cos(arc * Math.PI / 180));
y = (float) (centerY + radius * Math.sin(arc * Math.PI / 180));
二.整個代碼(尊重別人勞動成果,轉載請注明 處(http://blog.csdn.net/u010949962/article/details/42198235):
package xu.ye.view.ui; import java.util.HashMap; import xu.ye.R; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.os.Handler; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.ImageButton; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; /** * @author huangxin */ public class QuickAlphabeticBar extends ImageButton { public static final String TAG = QuickAlphabeticBar; public static final int DEFAULT_SCREEN_HEIGHT = 800; public static final int DEFAULT_TEXT_SIZE = 20; private TextView mDialogText; private Handler mHandler; private ListView mList; private float mHight; private String[] letters = new String[] { #, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z }; private HashMapalphaIndexer; private float centerXY[] = null; private int singleHeight; private int height; private int width; private float arc = 0; private float radius; private float normalWidth; private float selectedWidth; private boolean isselectedState = false; private int textSize; private int startPos = -1; private int endPos = -1; private Context context; private float measureTextSize = -1; private int screenWidth; private int screenHeight; public QuickAlphabeticBar(Context context) { super(context); init(context); } public QuickAlphabeticBar(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public QuickAlphabeticBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public void setScreenWidth(int screenWidth) { this.screenWidth = screenWidth; } public void setScreenHeight(int screenHeight) { this.screenHeight = screenHeight; } private void init(Context context){ this.context = context; //textSize = getTextSizeFormRatio(); textSize = 10; normalWidth = getResources().getDimensionPixelSize(R.dimen.azbar_normal_width); selectedWidth = getResources().getDimensionPixelSize(R.dimen.azbar_selected_width); } public void init(Activity ctx) { mDialogText = (TextView) ctx.findViewById(R.id.fast_position); mDialogText.setVisibility(View.INVISIBLE); mHandler = new Handler(); } public void setListView(ListView mList) { this.mList = mList; } public void setAlphaIndexer(HashMap alphaIndexer) { this.alphaIndexer = alphaIndexer; } public void setHight(float mHight) { this.mHight = mHight; } @Override public boolean onTouchEvent(MotionEvent event) { int act = event.getAction(); float y = event.getY(); float x = event.getX(); final int oldChoose = choose; singleHeight = height / letters.length; radius = 8 * singleHeight / 2; int selectIndex = (int) (y / (mHight / letters.length)); if (selectIndex > -1 && selectIndex < letters.length) { String key = letters[selectIndex]; if (alphaIndexer.containsKey(key)) { int pos = alphaIndexer.get(key); if (mList.getHeaderViewsCount() > 0) { this.mList.setSelectionFromTop( pos + mList.getHeaderViewsCount(), 0); } else { this.mList.setSelectionFromTop(pos, 0); } } mDialogText.setText(letters[selectIndex]); arc = 0; if(!isselectedState){ isselectedState = true; //int selected = (int) (centerXY[0] - (radius + paint.measureText(letters[selectIndex]))); setLayoutParams((int) selectedWidth); } } switch (act) { case MotionEvent.ACTION_DOWN: showBkg = true; if (oldChoose != selectIndex) { if (selectIndex >= 0 && selectIndex < letters.length) { choose = selectIndex; invalidate(); } } if (mHandler != null) { mHandler.post(new Runnable() { @Override public void run() { if (mDialogText != null && mDialogText.getVisibility() == View.INVISIBLE) { mDialogText.setVisibility(VISIBLE); } } }); } break; case MotionEvent.ACTION_MOVE: if(x < selectedWidth * 0.5 && isselectedState){ reseAlphabeticBar(); return super.onTouchEvent(event); } if (oldChoose != selectIndex) { if (selectIndex >= 0 && selectIndex < letters.length) { choose = selectIndex; invalidate(); } } break; case MotionEvent.ACTION_UP: reseAlphabeticBar(); break; case MotionEvent.ACTION_CANCEL: reseAlphabeticBar(); break; default: break; } return super.onTouchEvent(event); } private void reseAlphabeticBar(){ centerXY = null; showBkg = false; choose = -1; isselectedState = false; arc = 0; setLayoutParams((int) normalWidth); if (mHandler != null) { mHandler.post(new Runnable() { @Override public void run() { if (mDialogText != null && mDialogText.getVisibility() == View.VISIBLE) { mDialogText.setVisibility(INVISIBLE); invalidate(); } } }); } } private void setLayoutParams(int width){ RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(width, RelativeLayout.LayoutParams.MATCH_PARENT); lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); lp.addRule(RelativeLayout.BELOW, R.id.acbuwa_topbar); setLayoutParams(lp); } //TODO: Paint paint = new Paint(); boolean showBkg = false; int choose = -1; protected void onDraw(Canvas canvas) { super.onDraw(canvas); /*if (showBkg) {//???ñ???????? canvas.drawColor(Color.parseColor(#b20264)); }*/ height = getHeight(); width = (int) getWidth(); getStartAndEndPosFromArg(); boolean flag = false; for (int i = 0; i < letters.length; i++) { paint.setColor(getResources().getColor(android.R.color.black)); paint.setTextSize(textSize); Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL); paint.setTypeface(font); paint.setAntiAlias(true); measureTextSize = paint.measureText(letters[i]); float xPos, yPos; if(isselectedState){ xPos = selectedWidth - normalWidth / 2 - measureTextSize / 2; }else{ xPos = normalWidth / 2 - measureTextSize / 2; } yPos = singleHeight * i + singleHeight; if (i == choose) { paint.setColor(Color.parseColor(#00BFFF)); paint.setFakeBoldText(true); } if((i >= startPos && i <= endPos) && choose != -1 && isselectedState){ if(centerXY == null){ centerXY = new float[2]; centerXY[0] = selectedWidth - normalWidth / 2 - measureTextSize / 2; centerXY[1] = singleHeight * choose + singleHeight; } if (!flag) { getStartPosFromArg(startPos); flag = true; } float[] arcXY = getXYFormArg(); xPos = arcXY[0]; yPos = arcXY[1]; arc = (float) (arc - 22.5); int size = getArgLetterTextSize(i); paint.setTextSize(size); } canvas.drawText(letters[i], xPos, yPos, paint); paint.reset(); } centerXY = null; } private void getStartAndEndPosFromArg(){ if(choose != -1){ if(choose <= 3){ startPos = 0; }else{ startPos = choose - 3; } if(choose - letters.length + 4 <= 0){ endPos = choose + 3; }else{ endPos = letters.length -1; } } } private void getStartPosFromArg(int startPos) { if (startPos == choose) { arc = 180; } else if (startPos + 1 == choose) { arc = (float) 202.5; } else if (startPos + 2 == choose) { arc = 225; } else if (startPos + 3 == choose) { arc = (float) 247.5; } } private int getArgLetterTextSize(int i){ if(i == choose){ return textSize + 8; }else if(i + 1 == choose || choose + 1 == i){ return textSize + 6; }else if(i + 2== choose || choose + 2 == i){ return textSize + 4; }else if(i + 3== choose || choose + 3 == i){ return textSize + 4; } return textSize; } private float[] getXYFormArg(){ float[] xy = new float[2]; xy[0] = (float) (centerXY[0] + radius * Math.cos(arc * Math.PI / 180)); xy[1] = (float) (centerXY[1] + radius * Math.sin(arc * Math.PI / 180)); return xy; } }
ContentProvider基本使用為了在應用程序之間交換數據,android提供了ContentProvider,ContentProvider是不同應用程序之間進行
本文實例為大家分享了Android動態GridView控件使用的具體代碼,供大家參考,具體內容如下MainActivity.java代碼:package siso.hah
Android基礎入門教程——2.4.7 構建一個可復用的自定義BaseAdapter標簽(空格分隔): Android基礎入門教程本節引言: 如
本文主要講解局部加權(線性)回歸。在講解局部加權線性回歸之前,先講解兩個概念:欠擬合、過擬合,由此引出局部加權線性回歸算法。 欠擬合、過擬合如下圖中三個擬合模型