Android自定義半圓形圓盤滾動選擇器View
前段時間公司專案要求做一個特效的滑動選擇器,效果如下圖的樣子:
功能要求:兩邊的半圓形轉盤可以轉動,轉盤上的圖示也一起滾動,藍紅色圖示指著的小圖示變成高亮選中狀態。
第一眼看到這個需求就想到這個必須要用自定義控制元件來做才行,於是產生了這樣的思路:
半圓形的滾動的轉盤自定義view繼承viewgroup,重寫滑動事件,自定義圓盤上圖片的擺放角度,至於藍色和紅色箭頭圖示指向的選中狀態可以用座標陣列繪製一個區域來判斷是否有符合條件的圖示滾動到了這個位置,如果有的話就將這個圖示所在的控制元件透明度設定為1,如果沒到這個位置就設定為非選中狀態0.5透明度 ,思路這樣定下來了,預計可以行得通,於是開始進行實際的嘗試寫程式碼實現這個自定義的控制元件和功能。
下面我直接把核心程式碼附上,註釋比較清晰:
attrs.xml檔案程式碼:
<!--自定義半圓形展示效果轉盤選擇器控制元件-->
<declare-styleable name="ringview_half">
<attr name="image_angle_rh" format="integer" />
<attr name="image_padding_rh" format="integer" />
<attr name="max_speed_rh" format="integer" />
<attr name="min_speed_rh" format="integer" />
<attr name="list_rh" format="integer" />
<attr name="can_scroll_rh" format="boolean" />
<attr name="is_right_select_icon_rh" format="boolean" />
</declare-styleable>
自定義控制元件的類程式碼:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.wj.R;
import com.wj.utils.DensityUtil;
import com.wj.utils.ScreenUtils;
import java.util.ArrayList;
import java.util.List;
/**
* @time 2018/6/8
* @author JunJieW
* @since [email protected]
* @description 自定義半圓形展示效果轉盤選擇器控制元件
*/
public class RingViewHalf extends ViewGroup {
/**
* 上一次滑動的座標
*/
private float mLastX;
private float mLastY;
/**
* 檢測按下到擡起時使用的時間
*/
private long mDownTime;
/**
* 自動滾動執行緒
*/
private ScrollResetRunnable mScrollResetRunnable;
/**
* 檢測按下到擡起時旋轉的角度
*/
private float mTmpAngle;
/**
* 每秒最大移動角度
*/
private int mMax_Speed;
/**
* 如果移動角度達到該值,則遮蔽點選
*/
private int mMin_Speed;
/**
* 圓的直徑
*/
private int mRadius;
/**
* 判斷是否正在自動滾動
*/
private boolean isMove;
/**
* 佈局滾動角度
*/
private int mStartAngle = 0;
/**
* 中間條的寬度
*/
private int mCircleLineStrokeWidth;
/**
* 圖片內容偏移角度
*/
private int mImageAngle;
/**
* 是否初始化佈局
*/
private boolean isChekc = false;
/**
* 佈局view
*/
private List<Integer> mImageList = new ArrayList<>();
/**
* 是否可點選
*/
private boolean isCanClick = true;
/**
* 圖片與環之間的padding
*/
private int mPadding;
/**
* 是否是右邊居中的圖示為選中圖示
*/
private boolean is_right_select_icon = true;
/**
* 是否是右邊居中的圖示為選中圖示
*/
private Rect select_icon_rect = new Rect();
//是否能轉動
private boolean mCanScrool;
public RingViewHalf(Context context) {
this(context, null, 0);
}
public RingViewHalf(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RingViewHalf(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//獲取自定義控制元件設定的值
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ringview_half, 0, 0);
mMax_Speed = array.getInteger(R.styleable.ringview_half_max_speed_rh, 300);
mMin_Speed = array.getInteger(R.styleable.ringview_half_min_speed_rh, 3);
mImageAngle = array.getInteger(R.styleable.ringview_half_image_angle_rh, 0);
mPadding = array.getInteger(R.styleable.ringview_half_image_padding_rh, 0);
mCanScrool = array.getBoolean(R.styleable.ringview_half_can_scroll_rh, true);
is_right_select_icon = array.getBoolean(R.styleable.ringview_half_is_right_select_icon_rh, true);
//獲取xml定義的資原始檔
TypedArray mList = context.getResources().obtainTypedArray(array.getResourceId(R.styleable.ringview_half_list_rh, 0));
int len = mList.length();
if (len > 0) {
for (int i = 0; i < len; i++)
mImageList.add(mList.getResourceId(i, 0));
} else {
mImageList.add(R.mipmap.icon);
mImageList.add(R.mipmap.icon);
mImageList.add(R.mipmap.icon);
}
mList.recycle();
array.recycle();
int [] location =new int [2];
getLocationInWindow(location);
Log.d("locationInWindow",">>>>X=="+location[0]+"y=="+location[1]);
addImgIcon();
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (!isChekc) {
initView();
mRadius = getWidth();
isChekc = true;
}
}
/**
* 測量
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int childCount = this.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = this.getChildAt(i);
this.measureChild(child, widthMeasureSpec, heightMeasureSpec);
child.getMeasuredWidth();
}
}
/**
* 排版佈局
*/
private void initView() {
int width = this.getWidth();
int height = this.getHeight();
if (width != height) {
int min = Math.min(width, height);
width = min;
height = min;
}
//不同螢幕解析度下做不同的處理
float instPadding = 70f;
if (ScreenUtils.getScreenWidth(getContext())<=720){
instPadding = 55f;
}
//圖片擺放的圓弧半徑
mCircleLineStrokeWidth = getChildAt(0).getMeasuredHeight() + DensityUtil.dip2px(getContext(),instPadding) + mPadding;
//計算圖片圓的半徑
final int mContent = width / 2 - mCircleLineStrokeWidth / 2;
for (int i = 0; i < getChildCount(); i++) {
View child = this.getChildAt(i);
//計算每個圖片擺放的角度
int mAnGle = 360 / mImageList.size() * (i + 1) + mImageAngle;
//獲取每個圖片擺放的左上角的x和y座標
float left = (float) (width / 2 + mContent * Math.cos(mAnGle * Math.PI / 180)) - child.getMeasuredWidth() / 2;
float top = (float) (height / 2 + mContent * Math.sin(mAnGle * Math.PI / 180)) - child.getMeasuredHeight() / 2;
/**
* 一四象限
*/
if (getQuadrantByAngle(mAnGle) == 1 || getQuadrantByAngle(mAnGle) == 4) {
// child.setRotation(mAnGle - 270);
/**
* 二三象限
*/
} else {
// child.setRotation(mAnGle + 90);
}
child.layout((int) left, (int) top, (int) left + child.getMeasuredWidth(), (int) top + child.getMeasuredHeight());
}
}
/**
* 新增子控制元件
*/
private void addImgIcon() {
for (int i = 1; i < mImageList.size() + 1; i++) {
//新建imageview
final ImageView mImageView = new ImageView(getContext());
mImageView.setImageResource(mImageList.get(i - 1));
LayoutParams layoutParams = null;
mImageView.setScaleType(ImageView.ScaleType.FIT_XY);
if (is_right_select_icon){
//右側icon為選中狀態
if (i==mImageList.size()){
mImageView.setAlpha(1f);
layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
}else {
mImageView.setAlpha(0.5f);
layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
}
}else {
// 左側icon為選中狀態
if (i==5){
mImageView.setAlpha(1f);
layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
}else {
mImageView.setAlpha(0.5f);
layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
}
}
mImageView.setLayoutParams(layoutParams);
final int finalI = i;
//新增點選事件
mImageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (isCanClick) {
// Toast.makeText(getContext(),finalI + " ---", Toast.LENGTH_SHORT).show();
if (mOnLogoItemClick != null)
mOnLogoItemClick.onItemClick(view, finalI - 1);
}
}
});
//新增view
addView(mImageView);
}
//新增view點選事件
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (isCanClick) {
}
}
});
}
/**
* 觸控監聽
*/
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (mCanScrool) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastX = x;
mLastY = y;
mDownTime = System.currentTimeMillis();
mTmpAngle = 0;
// 如果當前已經在快速滾動
if (isMove) {
// 移除快速滾動的回撥
removeCallbacks(mScrollResetRunnable);
isMove = false;
return true;
}
break;
case MotionEvent.ACTION_MOVE:
/**
* 獲得開始的角度
*/
float start = getAngle(mLastX, mLastY);
/**
* 獲得當前的角度
*/
float end = getAngle(x, y);
Log.e("TAG", "start = " + start + " , end =" + end);
// 一四象限
if (getQuadrant(x, y) == 1 || getQuadrant(x, y) == 4) {
mStartAngle += end - start;
mTmpAngle += end - start;
//二三象限
} else {
mStartAngle += start - end;
mTmpAngle += start - end;
}
// 重新佈局
getCheck();
break;
case MotionEvent.ACTION_UP:
// 獲取每秒移動的角度
float anglePerSecond = mTmpAngle * 1000
/ (System.currentTimeMillis() - mDownTime);
// 如果達到最大速度
if (Math.abs(anglePerSecond) > mMax_Speed && !isMove) {
// 慣性滾動
post(mScrollResetRunnable = new ScrollResetRunnable(anglePerSecond));
return true;
}
// 如果當前旋轉角度超過minSpeed遮蔽點選
if (Math.abs(mTmpAngle) > mMin_Speed) {
return true;
}
break;
}
}
return super.dispatchTouchEvent(event);
}
/**
* 獲取移動的角度
*/
private float getAngle(float xTouch, float yTouch) {
double x = xTouch - (mRadius / 2d);
double y = yTouch - (mRadius / 2d);
return (float) (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);
}
/**
* 根據當前位置計算象限
*/
private int getQuadrant(float x, float y) {
int tmpX = (int) (x - mRadius / 2);
int tmpY = (int) (y - mRadius / 2);
if (tmpX >= 0) {
return tmpY >= 0 ? 4 : 1;
} else {
return tmpY >= 0 ? 3 : 2;
}
}
/**
* 在activity的onCreate方法中獲取當前自定義view中在螢幕中的絕對座標始終為0,
* 改成在onWindowFocusChanged函式中獲取即可,這時view都已經載入完成
* 但這裡特別注意一點要:如果是fragment種使用該自定義view的話,這裡的方法就應該註釋掉
* 因為不但獲取到的矩形的值是空的,而且當你的fragment執行了跳轉的邏輯後,再返回後會發
* 一種特別噁心的異常,你獲取到判斷選中位置的矩形的left,top,right,bottom的值會和
* 初始化的時候不一樣,導致你選中時候的狀態出現異常情況,本人已經被坑過,希望後面的同學
* 一定注意吸取教訓
*/
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
getSelectIconReft();
}
//獲取選中icon位置的矩形範圍
private void getSelectIconReft() {
int [] location = new int [2];
getLocationOnScreen(location);
//計算出右側選中時圖示的位置
if (is_right_select_icon){
//選中的icon動態設定寬高為60,沒選中寬高55,這裡60/2為選中按鈕的寬度或者高度的一半,即中心點
select_icon_rect.left = location[0]+getWidth()-mCircleLineStrokeWidth/2-DensityUtil.dip2px(getContext(),40f)/2;
select_icon_rect.top =(location[1]+getHeight()/2)-DensityUtil.dip2px(getContext(),40f)/2;
select_icon_rect.right = location[0]+getWidth()-mCircleLineStrokeWidth/2+DensityUtil.dip2px(getContext(),40f)/2;
select_icon_rect.bottom = (location[1]+getHeight()/2)+DensityUtil.dip2px(getContext(),40f)/2;
}else {
//計算出左側選中時圖示的位置
//選中的icon動態設定寬高為60,沒選中寬高55,這裡60/2為選中按鈕的寬度或者高度的一半,即中心點
select_icon_rect.left = location[0]+mCircleLineStrokeWidth/2-DensityUtil.dip2px(getContext(),40f)/2;
select_icon_rect.top = (location[1]+getHeight()/2)-DensityUtil.dip2px(getContext(),40f)/2;
select_icon_rect.right = location[0]+mCircleLineStrokeWidth/2+DensityUtil.dip2px(getContext(),40f)/2;
select_icon_rect.bottom = (location[1]+getHeight()/2)+DensityUtil.dip2px(getContext(),40f)/2;
}
Log.d("onFocusChanged","-----getHeight=="+getChildAt(0).getHeight()+";getWidth=="+getChildAt(0).getWidth());
}
/**
* 通過角度判斷象限
*/
private int getQuadrantByAngle(int angle) {
if (angle <= 90) {
return 4;
} else if (angle <= 180) {
return 3;
} else if (angle <= 270) {
return 2;
} else {
return 1;
}
}
/**
* 慣性滾動
*/
private class ScrollResetRunnable implements Runnable {
private float angelPerSecond;
public ScrollResetRunnable(float velocity) {
this.angelPerSecond = velocity;
}
public void run() {
//小於20停止
if ((int) Math.abs(angelPerSecond) < 20) {
isMove = false;
return;
}
isMove = true;
// 滾動時候不斷修改滾動角度大小
// mStartAngle += (angelPerSecond / 30);
mStartAngle += (angelPerSecond / 40);
//逐漸減小這個值
angelPerSecond /= 1.0666F;
postDelayed(this, 30);
// 重新佈局
getCheck();
}
}
/**
* 點選事件介面
*/
public interface OnLogoItemClick {
void onItemClick(View view, int pos);
}
private OnLogoItemClick mOnLogoItemClick;
private OnIconSelectedListener mOnIconSelectedListener;
/**
* 設定點選事件
* @param mOnLogoItemClick
*/
public void addOnItemClick(OnLogoItemClick mOnLogoItemClick) {
this.mOnLogoItemClick = mOnLogoItemClick;
}
/**
* 到選中位置後選中事件介面
*/
public interface OnIconSelectedListener{
void onIconSelected( int pos);
}
/**
* 設定點選事件
* @param mOnIconSelectedListener
*/
public void addOnIconSelectedListener(OnIconSelectedListener mOnIconSelectedListener) {
this.mOnIconSelectedListener = mOnIconSelectedListener;
}
/**
* 旋轉圓盤
*/
private void getCheck() {
mStartAngle %= 360;
setRotation(mStartAngle);
//改變選中的icon的狀態
setSelectedIcon();
}
//改變選中的icon的狀態
private void setSelectedIcon() {
if (select_icon_rect.left==0&&select_icon_rect.top==0){
//fragment中onWindowFocusChanged會出現計算select_icon_rect.left和select_icon_rect.top等於0的情況,
// 所以做下判斷,如果為0則重新呼叫下計算方法
getSelectIconReft();
}
for (int j =0;j<getChildCount();j++){
LayoutParams layoutParams = null;
int [] location = new int [2];
getChildAt(j).getLocationOnScreen(location);
Log.d("getCheck","location[0]=="+location[0]+";select_icon_rect.left=="+select_icon_rect.left+"location[1]=="+location[1]+";select_icon_rect.top=="+select_icon_rect.top);
if (is_right_select_icon){
//右邊icon是選中狀態的時候
if (select_icon_rect.left-22<=location[0]&&location[0]<=select_icon_rect.right+22){
if (select_icon_rect.top-22<=location[1]&&location[1]<=select_icon_rect.bottom+22){
getChildAt(j).setAlpha(1);
layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
//把選中的icon所在list中的position通過介面回傳過去
if (mOnIconSelectedListener!=null){
mOnIconSelectedListener.onIconSelected(j);
}
}else {
getChildAt(j).setAlpha(0.5f);
layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
}
}else {
getChildAt(j).setAlpha(0.5f);
layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
}
}else {
//左邊icon是選中狀態的時候
if (select_icon_rect.left-22<=location[0]&&location[0]<=select_icon_rect.right+22){
if (select_icon_rect.top-22<=location[1]&&location[1]<=select_icon_rect.bottom+22){
getChildAt(j).setAlpha(1);
layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
//把選中的icon所在list中的position通過介面回傳過去
if (mOnIconSelectedListener!=null){
mOnIconSelectedListener.onIconSelected(j);
}
}else {
getChildAt(j).setAlpha(0.5f);
layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
}
}else {
getChildAt(j).setAlpha(0.5f);
layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
}
}
getChildAt(j).setLayoutParams(layoutParams);
getChildAt(j).invalidate();
Log.d("getChildCount","=="+j+";class=="+getChildAt(j).getClass()+";left=="+getChildAt(j).getLeft()+";top=="+getChildAt(j).getTop()+";right=="+getChildAt(j).getRight()+";bottom=="+getChildAt(j).getBottom()+";getLocationOnScreen:x="+location[0]+"y="+location[1]+";getRotationX=="+getRotationX()+";getRotationY=="+getRotationY());
}
}
}
然後就是你在activity中根據回撥方法獲取選中的物件:
//左右側方法相同,這裡列出左側圓盤獲取方法:
view.ringView_half_left.addOnIconSelectedListener { position ->
// ToDo 根據postion從你的list中獲取對應的選中的物件的bean類屬性即可
}
最後貼下佈局檔案:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/ring_left_outside_rl"
android:layout_width="@dimen/dp_350"
android:layout_height="@dimen/dp_350"
android:layout_alignParentLeft="true"
android:layout_marginLeft="-240dp">
<com.wj.views.RingViewHalf
android:id="@+id/ringView_half_left"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_compatibility"
app:image_angle_rh="15"
app:image_padding_rh="20"
app:is_right_select_icon_rh="true"
app:list_rh="@array/zodiac_list" />
<ImageView
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/dp_220"
android:src="@drawable/icon_match_boy" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/ring_right_outside_rl"
android:layout_width="@dimen/dp_350"
android:layout_height="@dimen/dp_350"
android:layout_alignParentRight="true"
android:layout_marginRight="-240dp">
<com.wj.views.RingViewHalf
android:id="@+id/ringView_half_right"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/bg_compatibility"
app:image_angle_rh="15"
app:image_padding_rh="20"
app:is_right_select_icon_rh="false"
app:list_rh="@array/zodiac_list" />
<ImageView
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="@dimen/dp_220"
android:src="@drawable/icon_match_girl" />
</RelativeLayout>
<Button
android:id="@+id/check_btn"
android:layout_width="@dimen/dp_265"
android:layout_height="@dimen/dp_46"
android:layout_alignParentBottom="true"
android:layout_marginBottom="@dimen/dp_25"
android:layout_marginTop="@dimen/dp_25"
android:layout_centerHorizontal="true"
android:alpha="0.5"
android:enabled="true"
android:clickable="true"
android:background="@drawable/check" />
</RelativeLayout>
//這裡是放半圓形轉盤選擇器上顯示的圖片list,我這裡是用的xml靜態傳進去的,也可以改為動態方式傳遞
app:list_rh="@array/zodiac_list"
然後在values下面建立一個arrays.xml檔案
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="zodiac_list">
<item>@drawable/zodiac_1</item>
<item>@drawable/zodiac_2</item>
<item>@drawable/zodiac_3</item>
<item>@drawable/zodiac_4</item>
<item>@drawable/zodiac_5</item>
<item>@drawable/zodiac_6</item>
<item>@drawable/zodiac_7</item>
<item>@drawable/zodiac_8</item>
<item>@drawable/zodiac_9</item>
<item>@drawable/zodiac_10</item>
<item>@drawable/zodiac_11</item>
<item>@drawable/zodiac_12</item>
</string-array>
</resources>
到此就可以了~
喜歡的可以在文章底部留言交流或者探討,需要demo原始碼的留言跟我要就行~
相關推薦
Android自定義半圓形圓盤滾動選擇器View
前段時間公司專案要求做一個特效的滑動選擇器,效果如下圖的樣子: 功能要求:兩邊的半圓形轉盤可以轉動,轉盤上的圖示也一起滾動,藍紅色圖示指著的小圖示變成高亮選中狀態。 第一眼看到這個需求就想到這個必須要用自定義控制元件來做才
Android自定義控制元件實戰——滾動選擇器PickerView
手機裡設定鬧鐘需要選擇時間,那個選擇時間的控制元件就是滾動選擇器,前幾天用手機刷了MIUI,發現自帶的那個時間選擇器效果挺好看的,於是就自己仿寫了一個,權當練手。先來看效果:
Android 自定義控件之 日期選擇控件
gin pri 選中 att files ger bottom null count() 效果如下: 調用的代碼: @OnClick(R.id.btn0) public void btn0() { final AlertDialog dialog
Android 自定義數字圓環
最近專案中寫了一個數字圓環的樣式,只能通過自定義View完成,對於自定義View我還比較薄弱,查了一些資料,我們參考下: 看下效果圖: 自定義View:DoughnutView.java /** * on 15/12/16. * 自定義數字圓環 * 參考:
Android -- 自定義實現橫豎雙向滾動的列表(ListView)佈局
public class CustomHScrollView extends HorizontalScrollView { ScrollViewObserver mScrollViewObserver = new ScrollViewObserver(); public CustomHSc
Android 自定義確認提示框,選擇確認
效果圖: 工具類: import android.app.AlertDialog.Builder; import android.app.Dialog; import android.content.Context; import android.grap
Android自定義介面卡---實現簡單檔案管理器
一、介面卡Adapter 現實生活中的介面卡就是一種“轉化器”,將兩個不相容的事物做一個連線。Android在檢視顯示和後臺資料上使用介面卡,顧名思義,就是把一些資料給變得適當,適合以便於在View上顯示。可以看作是介面資料繫結的一種理解。它所操縱的資料一般
android 自定義view實現圓盤抽獎的效果
廢話不多說直接上程式碼。 import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import andro
Android 仿 iphone 自定義滾動選擇器
背景:其實我們都知道,在我們做開發的過程中,會遇到Android 自身所帶控制元件不夠的情況,那麼這個時候,就需要我們自定義控制元件,所以,也就造成了,在開發的過程中,我們一定要掌握好自定義控制元件,不然,當你去一家公司,產品萌妹子過來找你,這個效果很不錯,問你能不能實
Android自定義View實戰---圓盤溫度計
瞭解了基本的自定義view基礎後,現在我們就來實踐下自定義view,也是看到我華為手機上自帶的天氣預報軟體後,想著模仿做一個,於是,我自己嘗試了下,雖然不算太像,但是還算能看,期待後期的改進。 通過本文你可以用到以下技術: 1)view的測量 2)canvas繪圖技巧 3)
Android自定義View圓盤滑動控制元件(已適配多種解析度)
好久沒寫部落格了,最近在寫一個專案時需要一個可以調節檔位的圓盤, 首先實現這個圓盤自定義View,首先在構造方法中定義畫筆,重寫onDraw(Canvas canvas)方法,進行繪製,首先繪製一個大圓,然後我這個大圓周圍的錶盤顯示一共有9個檔位,為了美觀,每個
Android 自定義含有滾動選擇器的對話方塊
1.概述 使用LIstView和Dialog實 自定義含有滾動選擇器的對話方塊,可以設定顯示字型的不同顏色,設定字型透明度,設定大小,設定顯示多少項。下面給兩個效果: 顯示7項,字型透明度和大小改變 顯示5項,字型顏色和大小改變
Android 自定義view之圓盤進度條
很久沒有用到自定義View了,手有點生疏了,這不同事剛扔給一個活,按照UI的要求,畫一個進度條,帶動畫效果的。需求是這樣的: 嗯,實現後效果如下: 嗯,算是基本滿足需求吧。 本文包含的知識點 1、自定義view的繪製 2、屬性動畫 3、影象的
Android bc信用盤搭建自定義behavior 實現上滑 隱藏底部view
退出 Y軸 log rect app sum string dsl oss 布局 <android.support.design.widget.CoordinatorLayout android:layout_width="match_parent"
Android 自定義跑馬燈 實現超長文字,滾動完當前在繼續切換下一條
1 前言 最近專案上有一個跑馬燈的需求。 需求: 無限滾動,可以自動切換下一條 如果當前的文字超過一屏,則滾動完當前再切換下一條 第一點很簡單,但是第二點就比較蛋疼了,看了網上很多輪子都沒有太合適的,於是自己寫了一個。 記錄總結一下Android 跑馬燈的
【舉例】Android自定義Dialog——做出“確定/取消”的選擇
1、自定義Dialog的介面 <--!dialog_yesorno_for_permission.xml--> <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="
【舉例】Android自定義Dialog——選擇一個RadioButton
1. 自定義Dialog的介面 <--!dialog_selectserver.xml--> <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://sch
Android 自定義View例項之進度圓環
自定義View的相關文章: Android 實現一個簡單的自定義View Android 自定義View步驟 Android Paint詳解 Android 自定義View之Canvas相關方法說明 Android 自定義View例項之 “京東跑”
Android自定義帶有聯動時間選擇器(年,月,日,周,十,分)備錄
概述: 在日常的android開發中經常會遇到關於時間選擇的操作開發,比如和賬單記錄有關的記賬類軟體,以及進行鬧鐘定時任務的定時類軟體扥等。實現時間選擇器往往都會用到android.widget包中的NumPicker控制元件。關於NumPick
Android自定義DataTimePicker 日期選擇器
package com.wwj.datetimepicker;import java.text.SimpleDateFormat;import java.util.Calendar;import android.app.Activity;import android.app.AlertDialog;impor