編輯:關於Android編程
1- 整個自定義控件其實就是一個ArcMenu .(半圓形那一圈),左下角的圖標沒有加入進控件中。
2- 我基於他的類改了點。
他是將左下角的關閉icon都加入到整個自定義menu的layout中的,我是獨立出來
我menu中的item添加的思路是首先都給它固定在界面的最左邊,往屏幕左邊外面便宜半個item的寬度。然後在draw時,將每一個item的位置根據自身的角度,設置rotate值,不但外面要rotate到item本身應該所在的位置(pivot要設置為左下角為原點),它自身也得根據偏移的角度rotate到一個正確的向上的角度。其實在初始化時都給它們偏移過了。
3- 當然現在6.0、7.0上的那些自帶效果比我這漂亮多了,不過為了完成設計師給的設計稿,不得不這樣寫。所以輕噴。
4- 下面po上實現步驟。
a,自定義一個類ArcMenu繼承自FrameLayout.重載三個構造方法。
public class ArcMenu extends FrameLayout {
public ArcMenu(Context context) {super(context);}
public ArcMenu(Context context, AttributeSet attrs) {super(context, attrs);}
b,重寫 onSizeChanged方法,確定控件的高寬,並初始化控件中的一些參數
private void init() { if (!isInEditMode()) { for (int i = 0; i < ICON_COUNT; i++) {
//初始化默認和點擊的圖片bitmap m_iconGrayBitmaps[i] = DrawableManager.instance().getAssetBitmap(s_iconNamePrefixes[i] + "_gray.png"); m_iconWhiteBitmaps[i] = DrawableManager.instance().getAssetBitmap(s_iconNamePrefixes[i] + "_white.png"); // m_tangent[i] = Math.tan(90.0f / ICON_COUNT * i); } } m_arcWidth = m_height / 4;//弧形的寬度 // m_itemIndex = 0; m_startDegree = 90.0f / ICON_COUNT / 2; //第一個item初始化時應該待的位置的偏移角度 m_stepDegree = 90.0f / ICON_COUNT; //每一個item相對前一個item所偏移的角度
//新建一個矩形,中心點為左下角
m_arcRect = new RectF(-(m_width - m_arcWidth / 2), m_arcWidth / 2, m_width - m_arcWidth / 2, 2 * m_height - m_arcWidth / 2); int shadow_arc_width = Utils.dp2px(SHADOW_ARC_WIDTH); m_arcShadow = new RectF(-(m_width - m_arcWidth - shadow_arc_width / 2), m_arcWidth + shadow_arc_width / 2, (m_width - m_arcWidth - shadow_arc_width / 2), 2 * m_height - m_arcWidth - shadow_arc_width / 2); m_arcbgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); m_arcbgPaint.setStyle(Paint.Style.STROKE); m_arcbgPaint.setStrokeWidth(m_arcWidth); m_arcbgPaint.setColor(getResources().getColor(R.color.bg_menu_arc)); m_arcfgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); m_arcfgPaint.setStyle(Paint.Style.STROKE); m_arcfgPaint.setStrokeWidth(m_arcWidth); m_arcfgPaint.setColor(getResources().getColor(R.color.fg_menu_arc)); m_shadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); m_shadowPaint.setStyle(Paint.Style.STROKE); m_shadowPaint.setStrokeWidth(shadow_arc_width); m_shadowPaint.setColor(getResources().getColor(R.color.default_black)); setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { int index = pointInArc(event.getX(), event.getY()); if (index >= 0) { Logger.debug("click on icon " + index); m_itemIndex = index; invalidate(); m_itemClickedListener.onMenuItemClicked(index); return true; } } return false; } }); }
上面圖畫錯了。。綠色框其實就是外面的m_arcRect
shadowArc其實是 那一層黑色的arc..我懶得再畫了。。
接下來就是畫圖了。把那些item要畫上去,還得畫上這兩層弧形
用到dipatchDraw
@Override protected void dispatchDraw(Canvas canvas) { Path path = new Path(); /// draw out arc path.arcTo(m_arcRect, 270.0f, 90.0f); canvas.drawPath(path, m_arcbgPaint); canvas.drawArc(m_arcRect, 270.0f + m_stepDegree * m_itemIndex, m_stepDegree, false, m_arcfgPaint); /// draw shadow arc canvas.drawArc(m_arcShadow, 270.0f, 90.0f, false, m_shadowPaint); /// draw bitmaps for (int i = 0; i < ICON_COUNT; i++) { Bitmap bitmap; if (i == m_itemIndex) { /// selected icon bitmap = m_iconWhiteBitmaps[i]; } else { /// not selected bitmap = m_iconGrayBitmaps[i]; } if (bitmap != null) { Matrix matrix = new Matrix(); matrix.postTranslate(-bitmap.getWidth() / 2, (m_arcWidth - bitmap.getHeight()) / 2); matrix.postRotate(-m_startDegree - m_stepDegree * i, 0, m_arcWidth / 2); matrix.postRotate(m_startDegree + m_stepDegree * i, 0, m_height); canvas.drawBitmap(bitmap, matrix, null); } } super.dispatchDraw(canvas); }
寫到這裡不知道怎麼說了。。干脆貼代碼算了。
/** * check if point (x, y) is within arc icon * * @param x * @param y * @return index of the icon clicked, or -1 */ private int pointInArc(float x, float y) { float[] pts = {x, y}; float[] target_pts = new float[2]; Matrix matrix = new Matrix(); matrix.postRotate(-m_startDegree, 0, m_height); for (int i = 0; i < ICON_COUNT; i++) { matrix.mapPoints(target_pts, pts); if (pointInStartRectOfIcon(target_pts)) { return i; } matrix.postRotate(-m_stepDegree, 0, m_height); } return -1; } /** * check if (target_pts[0], target_pts[1]) is in the start position of icons * * @param target_pts * @return */ private boolean pointInStartRectOfIcon(float[] target_pts) { return target_pts[0] > -m_arcWidth / 2 && target_pts[0] < m_arcWidth / 2 && target_pts[1] > 0 && target_pts[1] < m_arcWidth; }
/** * Sets the click listener for menu items. */ public void setOnItemClickedListener(ArcMenuItemClickedListener itemClickedListener) { this.m_itemClickedListener = itemClickedListener; } public void setSelectedIcon(int index, boolean bInvalidate) { m_itemIndex = index; if(bInvalidate) { invalidate(); } }就醬吧。。。寫個博客煩球死。
工廠方法模式,往往是設計模式初學者入門的模式,的確,有人稱之為最為典型最具啟發效果的模式。android中用到了太多的工廠類,其中有用工廠方法模式的,當然也有很多工廠並不
本文實例為大家分享了Android自定義下拉刷新上拉加載的具體實現步驟,供大家參考,具體內容如下實現的方式是SwipeRefreshLayout + RecyclerVi
Android畫布翻轉是個利器,尤其在圖像處理上,不需要數組的轉置顛倒一堆線性變化就可以輕松實現原點的改變。就像醬紫,開始的時候,畫布妹妹是和顯示區哥哥重疊在一起的,默契
1、概述Android提供了幾種動畫類型:View Animation 、Drawable Animation 、Property Animation 。View An