編輯:關於Android編程
效果說明:滑竿指示器,是一段彎曲的圓弧,要求在桿上,有滑動小球事件,小球會根據下標文字的起始角度與終止角度,是否選擇滑倒下一個位置。當點擊下標文字時,小球也要做出相應的指示。
1)MainActivity
package com.example.chenkui.myapplication; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intIndicatorTabView(); // setContentView(R.layout.watch_view); } private void intIndicatorTabView() { IndicatorTabView view = (IndicatorTabView) findViewById(R.id.myView); Listlist = new ArrayList<>(); list.add("待評價"); list.add("待付款"); list.add("待發貨"); list.add("待收貨"); view.setTabInfo(list); view.setSelection(3);//初始化選擇指示器小球位置; view.setTabChangeListener(new IndicatorTabView.OnTabChangeListener() { @Override public void onTabSelected(View v, int position) { } }); } }
2)IndicatorTabView
在繪制時,按照圖層的結構,先繪制底層顏色,再繪制上一層圖形,對於特殊繪制的,如旋轉畫布,移動繪制圓心坐標,一般先 canvas.save();保存已經繪制圖層,canvas.restore();//他的作用為,將之前的繪制保存的圖片save(),進行合並.
package com.example.chenkui.myapplication; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import java.util.ArrayList; import java.util.List; public class IndicatorTabView extends View { private String TAG = IndicatorTabView.class.getSimpleName(); private static final float DEFAULT_SWEEP_ANGLE = 48.0f; private float mSweepAngle = DEFAULT_SWEEP_ANGLE; private float mStartAngle = (180.0f - mSweepAngle) / 2; private ListmTabItems = new ArrayList<>(); private int mSelectTabIndex = -1; private Paint mTabBackColorPaint; private Paint mTabPaint; private Paint mTabTtileTextPaint;//滑竿或點擊標題 private Paint mTabWheelPaint; private Paint mTabTextPaint; private Paint mTabPointerPaint; private float mWheelCenterX; private float mWheelCenterY; private float mWheelRadius; private RectF mWheelArcRect; private float mPointerAngle; private float mPointerRadius; private boolean mIsMovingPointer = false; private OnTabChangeListener mTabChangeListener = null; private List mTabRectItem = new ArrayList (); private Paint textPaint = new Paint(); private float mMinRectRadius;//文字區域, private float mMaxRectRadius;//文字區域, public IndicatorTabView(Context context) { this(context, null); } public IndicatorTabView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public IndicatorTabView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(); } private void initView() { mTabBackColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//繪制最大的裡邊圖層背景 mTabBackColorPaint.setStyle(Paint.Style.FILL); mTabBackColorPaint.setColor(Color.argb(255, 35, 47, 62)); mTabPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//繪制裡面最小圖層背景。 mTabPaint.setStyle(Paint.Style.FILL); mTabPaint.setColor(Color.argb(255, 253,253, 254)); mTabTtileTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//繪制裡面最小圖層背景。 mTabTtileTextPaint.setStyle(Paint.Style.FILL); mTabTtileTextPaint.setColor(Color.WHITE); mTabWheelPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTabWheelPaint.setStyle(Paint.Style.STROKE); mTabWheelPaint.setStrokeWidth(getResources().getDimension(R.dimen.tab_wheel_width)); mTabWheelPaint.setColor(Color.argb(200, 253, 250, 245)); mTabWheelPaint.setStrokeCap(Paint.Cap.ROUND);//這個是設置繪制弧是,兩端圓滑; mTabTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//繪制文字 mTabTextPaint.setColor(Color.argb(255, 253, 253, 254)); mTabTextPaint.setTextSize(getResources().getDimension(R.dimen.tab_text)); mTabTextPaint.setStrokeWidth(5); mTabPointerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//繪制小點 mTabPointerPaint.setStyle(Paint.Style.FILL); mTabPointerPaint.setColor(Color.argb(255, 255, 255, 255)); mPointerRadius = getResources().getDimension(R.dimen.tab_pointer_radius); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //繪制深藍背景。 canvas.drawCircle(mWheelCenterX, mWheelCenterY - getResources().getDimension(R.dimen.tab_wheel_padding_inner), mWheelRadius*1.2f, mTabBackColorPaint); //繪制裡面第一條弧 canvas.drawCircle(mWheelCenterX, mWheelCenterY - getResources().getDimension(R.dimen.tab_wheel_padding_inner), mWheelRadius, mTabPaint); canvas.drawArc(mWheelArcRect, mStartAngle, mSweepAngle, false, mTabWheelPaint);//繪制滑桿 for (int i = 0; i < mTabItems.size(); i++) { IndicatorTabItem tempItem = mTabItems.get(i); float angle = (tempItem.getStartAngle() + tempItem.getEndAngle()) / 2 - 90.0f; canvas.save();//將之前繪制圖片保存起來, canvas.rotate(angle, mWheelCenterX, mWheelCenterY); canvas.drawText(tempItem.getName(), mWheelCenterX - tempItem.getMesureWidth() / 2, getResources().getDimension(R.dimen.tab_wheel_width) + mWheelCenterY + mWheelRadius + getResources().getDimension(R.dimen.tab_wheel_padding_inner), mTabTextPaint); /***********************************************************************************************************/ Log.d(TAG, "-----------onDraw()-----------" + "X===[" + (mWheelCenterX - tempItem.getMesureWidth() / 2) + "]-------Y==={" + (getResources().getDimension(R.dimen.tab_wheel_width) + mWheelCenterY + mWheelRadius + getResources().getDimension(R.dimen.tab_wheel_padding_inner)) + "}"); float rectWidth = mTabTextPaint.measureText(tempItem.getName()); Paint.FontMetrics fm = mTabTextPaint.getFontMetrics(); float offsetAscent = fm.ascent; float offsetBottom = fm.bottom; float startX = mWheelCenterX - tempItem.getMesureWidth() / 2; float startY = getResources().getDimension(R.dimen.tab_wheel_width) + mWheelCenterY + mWheelRadius + getResources().getDimension(R.dimen.tab_wheel_padding_inner); Log.d(TAG, "TEXT-offsetAscent=" + offsetAscent); // RectF testRect = new RectF( // startX, // (float) (startY + offsetAscent), // (float) (startX + rectWidth), // (float) (startY + offsetBottom) // ); // textPaint.setColor(Color.argb(100, 233, 233, 0)); // canvas.drawRect(testRect, textPaint); /*************************************************************************************************************************/ canvas.restore();//他的作用為,將之前的繪制保存的圖片save(),進行合並. mMinRectRadius = distance(mWheelCenterX, startY + offsetAscent);//計算 mMaxRectRadius = distance(mWheelCenterX, startY + offsetBottom); } float[] pointerPosition = calculatePointerPosition(mPointerAngle); canvas.drawCircle(mWheelCenterX + pointerPosition[0], mWheelCenterY + pointerPosition[1], mPointerRadius, mTabPointerPaint);//繪制小球 } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); mWheelRadius = (float) (widthSize / (2.0f * Math.sin(Math.toRadians(32)))); int offset = (int) (heightSize - getResources().getDimension(R.dimen.tab_wheel_padding_bottom)); mWheelCenterY = offset - (int) Math.sqrt(Math.pow((double) mWheelRadius, 2) - Math.pow((double) (widthSize / 2), 2)); mWheelCenterX = widthSize / 2.0f; mWheelArcRect = new RectF(mWheelCenterX - mWheelRadius, mWheelCenterY - mWheelRadius, mWheelCenterX + mWheelRadius, mWheelCenterY + mWheelRadius); } private float[] calculatePointerPosition(float angle) { float x = (float) (mWheelRadius * Math.cos(Math.toRadians(angle))); float y = (float) (mWheelRadius * Math.sin(Math.toRadians(angle))); return new float[]{x, y}; } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX() - mWheelCenterX; float y = event.getY() - mWheelCenterY; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: float[] pointerPosition = calculatePointerPosition(mPointerAngle); if (x >= (pointerPosition[0] - mPointerRadius * 2) && x <= (pointerPosition[0] + mPointerRadius * 2) && y >= (pointerPosition[1] - mPointerRadius * 2) && y <= (pointerPosition[1] + mPointerRadius * 2)) { mIsMovingPointer = true; return true; } float pointerLength = distanceRelative(x, y);//計算觸摸點距離圓心的坐標: //計算文本觸摸區域的頂部距離圓心的坐標的距離: //計算文本觸摸區域的底部距離圓心的坐標的距離; //計算觸摸點的角度, float tempPointerRectFAngle = (float) Math.toDegrees(Math.atan2(y, x));//文本觸摸區域的的角度 if (pointerLength >= mMinRectRadius - mPointerRadius && pointerLength <= mMaxRectRadius + mPointerRadius) { int willSelectedIndex = -1; for (int i = 0; i < mTabRectItem.size(); i++) { IndicatorTabRectItem item = mTabRectItem.get(i); if (tempPointerRectFAngle >= item.getStartAngle() && tempPointerRectFAngle <= item.getEndAngle()) { willSelectedIndex = i; break; } } if (mSelectTabIndex != willSelectedIndex) { if (mTabChangeListener != null) { mTabChangeListener.onTabSelected(this, willSelectedIndex); } } setSelection(willSelectedIndex); invalidate(); return true; } break; case MotionEvent.ACTION_MOVE: if (mIsMovingPointer) { float tempPointerAngle = (float) Math.toDegrees(Math.atan2(y, x)); if (tempPointerAngle >= mTabItems.get(0).getStartAngle() && tempPointerAngle <= mTabItems.get(mTabItems.size() - 1).getEndAngle()) { mPointerAngle = tempPointerAngle; invalidate(); } return true; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (mIsMovingPointer) { mIsMovingPointer = false; smoothMove(); return true; } break; } return false; } /** * 根據觸摸點距離圓心的距離,與每一塊的活動角度,確定惟一的文本觸摸塊。 */ // private void calculateTouchRect(float x, float y) { //// =x-mWheelCenterX; // float dpow2 = (float) (Math.pow((x - mWheelCenterX), 2) + Math.pow((y - mWheelCenterY), 2)); // float d = (float) Math.sqrt(dpow2); // Log.d(TAG, "TouchRect---d=" + d); // Log.d(TAG, "mMinRectRadius====" + mMinRectRadius); // Log.d(TAG, "mMAXRectRadius====" + mMaxRectRadius); // // // } /** * 相對與(x-mWheelCenterX,y-mWheelCenterY)坐標, * 計算觸摸點。求兩點間距離,此時的圓心為 */ public float distanceRelative(float x, float y) { float dx = Math.abs(x); float dy = Math.abs(y); Log.d(TAG, "distance---d=" + (float) Math.hypot(dx, dy)); Log.d(TAG, "mMinRectRadius====" + mMinRectRadius); Log.d(TAG, "mMAXRectRadius====" + mMaxRectRadius); return (float) Math.hypot(dx, dy); } /** * 計算觸摸點。求兩點間距離 */ public float distance(float x, float y) { float dx = Math.abs(x - mWheelCenterX); float dy = Math.abs(y - mWheelCenterY); Log.d(TAG, "distance---d=" + (float) Math.hypot(dx, dy)); Log.d(TAG, "mMinRectRadius====" + mMinRectRadius); Log.d(TAG, "mMAXRectRadius====" + mMaxRectRadius); return (float) Math.hypot(dx, dy); } private void smoothMove() { int willSelectedIndex = -1; for (int i = 0; i < mTabItems.size(); i++) { IndicatorTabItem item = mTabItems.get(i); if (mPointerAngle >= item.getStartAngle() && mPointerAngle <= item.getEndAngle()) { willSelectedIndex = i; break; } } if (mSelectTabIndex != willSelectedIndex) { if (mTabChangeListener != null) { mTabChangeListener.onTabSelected(this, willSelectedIndex); } } setSelection(willSelectedIndex); } public void setTabInfo(List tabInfo) { if (tabInfo == null && (tabInfo.size() == 0 && tabInfo.size() > 4)) { return; } float totalPercent = 0.0f; for (int i = 0; i < tabInfo.size(); i++) { IndicatorTabItem item = new IndicatorTabItem(); item.setName(tabInfo.get(i)); item.setMesureWidth(mTabTextPaint.measureText(item.getName())); Log.d(TAG, "--------setTabInfo()-------" + item.getName()); totalPercent += item.getMesureWidth(); mTabItems.add(item); } float startAngle = mStartAngle; for (int i = 0; i < mTabItems.size(); i++) { IndicatorTabItem tempItem = mTabItems.get(i); float itemSweepAngle = mSweepAngle * tempItem.getMesureWidth() / totalPercent; tempItem.setStartAngle(startAngle); tempItem.setEndAngle(startAngle + itemSweepAngle); startAngle += itemSweepAngle; Log.d(TAG, "startAngle" + i + "======" + startAngle); Log.d(TAG, "EndAngle" + i + "======" + (startAngle + itemSweepAngle)); } setSelection(0); initIndicatorTabRectItem(tabInfo); } private void initIndicatorTabRectItem(List tabInfo) { if (tabInfo == null && (tabInfo.size() == 0 && tabInfo.size() > 4)) { return; } float totalPercent = 0.0f; for (int i = 0; i < tabInfo.size(); i++) { IndicatorTabRectItem rectItem = new IndicatorTabRectItem(); rectItem.setRectName(tabInfo.get(i)); rectItem.setRectWidth(mTabTextPaint.measureText(rectItem.getRectName())); totalPercent += rectItem.getRectWidth(); Log.d(TAG, "----initIndicatorTabRectItem--------setRectWidth" + i + "======" + mTabTextPaint.measureText(rectItem.getRectName())); mTabRectItem.add(rectItem); } float startAngle = mStartAngle; for (int i = 0; i < mTabRectItem.size(); i++) { IndicatorTabRectItem tempItem = mTabRectItem.get(i); float itemSweepAngle = mSweepAngle * tempItem.getRectWidth() / totalPercent; tempItem.setStartAngle(startAngle); tempItem.setEndAngle(startAngle + itemSweepAngle); startAngle += itemSweepAngle; Log.d(TAG, "----initIndicatorTabRectItem-------startAngle" + i + "======" + startAngle); Log.d(TAG, "----initIndicatorTabRectItem-------EndAngle" + i + "======" + (startAngle + itemSweepAngle)); } } /** * 設置選擇小點的每一段中心點角度。 * * @param index */ public void setSelection(int index) { if (index < 0 || index > mTabItems.size() - 1) { return; } mSelectTabIndex = index; mPointerAngle = (mTabItems.get(mSelectTabIndex).getStartAngle() + mTabItems.get(mSelectTabIndex).getEndAngle()) / 2; invalidate(); } public void setTabChangeListener(OnTabChangeListener tabChangeListener) { this.mTabChangeListener = tabChangeListener; } public interface OnTabChangeListener { void onTabSelected(View v, int position); } }
3)IndicatorTabRectItem
package com.example.chenkui.myapplication; /** * Created by chenkui on 2016/10/11. */ public class IndicatorTabRectItem { private float startX; private float endX; private float startY; private float endY; private float rectWidth; private float rectHeigth; private String rectName; private float startAngle; private float endAngle; public float getStartX() { return startX; } public void setStartX(float startX) { this.startX = startX; } public float getEndX() { return endX; } public void setEndX(float endX) { this.endX = endX; } public float getStartY() { return startY; } public void setStartY(float startY) { this.startY = startY; } public float getEndY() { return endY; } public void setEndY(float endY) { this.endY = endY; } public float getRectWidth() { return rectWidth; } public void setRectWidth(float rectWidth) { this.rectWidth = rectWidth; } public float getRectHeigth() { return rectHeigth; } public void setRectHeigth(float rectHeigth) { this.rectHeigth = rectHeigth; } public String getRectName() { return rectName; } public void setRectName(String rectName) { this.rectName = rectName; } public float getStartAngle() { return startAngle; } public void setStartAngle(float startAngle) { this.startAngle = startAngle; } public float getEndAngle() { return endAngle; } public void setEndAngle(float endAngle) { this.endAngle = endAngle; } }
4)IndicatorTabItem
package com.example.chenkui.myapplication; public class IndicatorTabItem { private String name; private float mesureWidth; private float startAngle; private float endAngle; public String getName() { return name; } public void setName(String name) { this.name = name; } public float getMesureWidth() { return mesureWidth; } public void setMesureWidth(float mesureWidth) { this.mesureWidth = mesureWidth; } public float getStartAngle() { return startAngle; } public void setStartAngle(float startAngle) { this.startAngle = startAngle; } public float getEndAngle() { return endAngle; } public void setEndAngle(float endAngle) { this.endAngle = endAngle; } }
5)activity_main.xml
dimen.xml
16dp 10dp 130dp 30dp 20dp 10dp
效果圖如下:
Android 中使用代碼動態布局 本文介紹在android中使用代碼動態布局,有時候根據不同的需求,比如需要根據服務器上的條目個數來決定app中頁面布局控件(
怎麼預防QQ號被盜,怎麼樣讓QQ號碼更加安全,手機qq設備鎖怎麼用?下面小編給大家帶來手機qq設備鎖設置教程,手機QQ4.62或以上版本才有此功能,一起來看
1.下拉列表Spinner 1.1.activity_main.xml Spinner是下拉列表的
android的gradle插件用了不少了,比如說官方的應用構建插件(com.android.application),lib構建插件(com.android.libra