Android滾輪選擇時(shí)間控件使用詳解
滾輪選擇控件
Android自帶的選擇時(shí)間控件有點(diǎn)丑,往往產(chǎn)品和設(shè)計(jì)都比較嫌棄,希望做成ios一樣的滾輪選擇,下面是我在NumberPicker的基礎(chǔ)上自定義的選擇控件,效果如下:

原理
- 基于NumberPicker實(shí)現(xiàn)
- 動(dòng)態(tài)填充數(shù)值
- 聯(lián)動(dòng)
- 接口監(jiān)聽回調(diào)
實(shí)現(xiàn)滾輪效果有g(shù)ithub上mark比較多的WheelView,但是閱讀源碼發(fā)現(xiàn)數(shù)據(jù)是一次性填入的,選擇時(shí)間的話,填入10年就是10*365=3650條數(shù)據(jù),也就是new出三千多個(gè)TextView,想想都覺得恐怖,肯定是不行的,于是便想到用NumberPicker,動(dòng)態(tài)填充數(shù)據(jù),一次只設(shè)置5個(gè)數(shù)據(jù),當(dāng)選中變化時(shí),重新設(shè)置數(shù)據(jù)填充,所以關(guān)鍵在于填充的數(shù)據(jù)的計(jì)算。
設(shè)置數(shù)據(jù)部分邏輯代碼:
/**
* 更新左側(cè)控件
* 日期:選擇年控件
* 時(shí)間:選擇月份和日期控件
*
* @param timeMillis
*/
private void updateLeftValue(long timeMillis) {
SimpleDateFormat sdf;
String str[] = new String[DATA_SIZE];
if (mCurrentType == TYPE_PICK_DATE) {
sdf = new SimpleDateFormat("yyyy");
for (int i = 0; i < DATA_SIZE; i++) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(timeMillis);
cal.add(Calendar.YEAR, (i - DATA_SIZE / 2));
str[i] = sdf.format(cal.getTimeInMillis());
}
} else {
sdf = new SimpleDateFormat("MM-dd EEE");
for (int i = 0; i < DATA_SIZE; i++) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(timeMillis);
cal.add(Calendar.DAY_OF_MONTH, (i - DATA_SIZE / 2));
str[i] = sdf.format(cal.getTimeInMillis());
}
}
mNpLeft.setDisplayedValues(str);
mNpLeft.setValue(DATA_SIZE / 2);
mNpLeft.postInvalidate();
}
對(duì)滾輪的監(jiān)聽,并重新設(shè)置填充數(shù)據(jù):
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(mTimeMillis);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int offset = newVal - oldVal;
if (picker == mNpLeft) {
if (mCurrentType == TYPE_PICK_DATE) {
calendar.add(Calendar.YEAR, offset);
} else {
calendar.add(Calendar.DAY_OF_MONTH, offset);
}
updateLeftValue(calendar.getTimeInMillis());
mTimeMillis = calendar.getTimeInMillis();
} else if (picker == mNpMiddle) {
if (mCurrentType == TYPE_PICK_DATE) {
calendar.add(Calendar.MONTH, offset);
if (calendar.get(Calendar.YEAR) != year) {
calendar.set(Calendar.YEAR, year);
}
} else {
calendar.add(Calendar.HOUR_OF_DAY, offset);
if (calendar.get(Calendar.DAY_OF_MONTH) != day) {
calendar.set(Calendar.DAY_OF_MONTH, day);
}
if (calendar.get(Calendar.MONTH) != month) {
calendar.set(Calendar.MONTH, month);
}
if (calendar.get(Calendar.YEAR) != year) {
calendar.set(Calendar.YEAR, year);
}
}
updateMiddleValue(calendar.getTimeInMillis());
updateRightValue(calendar.getTimeInMillis());
mTimeMillis = calendar.getTimeInMillis();
} else if (picker == mNpRight) {
if (mCurrentType == TYPE_PICK_DATE) {
int days = getMaxDayOfMonth(year, month + 1);
if(day == 1 && offset < 0){
calendar.set(Calendar.DAY_OF_MONTH,days);
}else if(day == days && offset > 0){
calendar.set(Calendar.DAY_OF_MONTH,1);
}else{
calendar.add(Calendar.DAY_OF_MONTH, offset);
}
if (calendar.get(Calendar.MONTH) != month) {
calendar.set(Calendar.MONTH, month);
}
if (calendar.get(Calendar.YEAR) != year) {
calendar.set(Calendar.YEAR, year);
}
Log.e(TAG,"time:::"+test.format(calendar.getTimeInMillis()));
} else {
calendar.add(Calendar.MINUTE, offset);
if (calendar.get(Calendar.HOUR_OF_DAY) != hour) {
calendar.set(Calendar.HOUR_OF_DAY, hour);
}
if (calendar.get(Calendar.DAY_OF_MONTH) != day) {
calendar.set(Calendar.DAY_OF_MONTH, day);
}
if (calendar.get(Calendar.MONTH) != month) {
calendar.set(Calendar.MONTH, month);
}
if (calendar.get(Calendar.YEAR) != year) {
calendar.set(Calendar.YEAR, year);
}
}
updateRightValue(calendar.getTimeInMillis());
mTimeMillis = calendar.getTimeInMillis();
}
/**
* 向外部發(fā)送當(dāng)前選中時(shí)間
*/
if (mOnSelectedChangeListener != null) {
mOnSelectedChangeListener.onSelected(this,mTimeMillis);
}
Log.e(TAG, "selected time:" + test.format(mTimeMillis));
}
選擇數(shù)值和字符串
同樣的,使用NumberPicker進(jìn)行封裝,動(dòng)態(tài)填充數(shù)值從而實(shí)現(xiàn)滾動(dòng)變換的效果。
- 考慮到通用性,傳入的是Object類型的數(shù)組,在控件里進(jìn)行判斷。
- 可以選擇一列數(shù)值、兩列數(shù)值、三列數(shù)值,字符串同理。每一列數(shù)值可以設(shè)置它的單位、標(biāo)題等,默認(rèn)是隱藏,需要自己設(shè)置。
- 可以設(shè)置步長(zhǎng)step
完整代碼如下:
package com.example.moore.picktimeview.widget;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.NumberPicker;
import android.widget.TextView;
/**
* Created by Moore on 2016/10/21.
*/
public class PickValueView extends LinearLayout implements NumberPicker.OnValueChangeListener {
private Context mContext;
/**
* 組件 標(biāo)題、單位、滾輪
*/
private TextView mTitleLeft, mTitleMiddle, mTitleRight;
private TextView mUnitLeft, mUnitMiddle, mUnitRight;
private MyNumberPicker mNpLeft, mNpMiddle, mNpRight;
/**
* 數(shù)據(jù)個(gè)數(shù) 1列 or 2列 or 3列
*/
private int mViewCount = 1;
/**
* 一組數(shù)據(jù)長(zhǎng)度
*/
private final int DATA_SIZE = 3;
/**
* 需要設(shè)置的值與默認(rèn)值
*/
private Object[] mLeftValues;
private Object[] mMiddleValues;
private Object[] mRightValues;
private Object mDefaultLeftValue;
private Object mDefaultMiddleValue;
private Object mDefaultRightValue;
/**
* 當(dāng)前正在顯示的值
*/
private Object[] mShowingLeft = new Object[DATA_SIZE];
private Object[] mShowingMiddle = new Object[DATA_SIZE];
private Object[] mShowingRight = new Object[DATA_SIZE];
/**
* 步長(zhǎng)
*/
private int mLeftStep = 5;
private int mMiddleStep = 1;
private int mRightStep = 1;
/**
* 回調(diào)接口對(duì)象
*/
private onSelectedChangeListener mSelectedChangeListener;
public PickValueView(Context context) {
super(context);
this.mContext = context;
generateView();
}
public PickValueView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
generateView();
}
public PickValueView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
generateView();
}
/**
* 生成視圖
*/
private void generateView() {
//標(biāo)題
LinearLayout titleLayout = new LinearLayout(mContext);
LayoutParams titleParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
titleParams.setMargins(0, 0, 0, dip2px(12));
titleLayout.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
titleLayout.setOrientation(HORIZONTAL);
mTitleLeft = new TextView(mContext);
mTitleMiddle = new TextView(mContext);
mTitleRight = new TextView(mContext);
LayoutParams params = new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1);
TextView[] titles = new TextView[]{mTitleLeft, mTitleMiddle, mTitleRight};
for (int i = 0; i < titles.length; i++) {
titles[i].setLayoutParams(params);
titles[i].setGravity(Gravity.CENTER);
titles[i].setTextColor(Color.parseColor("#3434EE"));
}
titleLayout.addView(mTitleLeft);
titleLayout.addView(mTitleMiddle);
titleLayout.addView(mTitleRight);
//內(nèi)容
LinearLayout contentLayout = new LinearLayout(mContext);
contentLayout.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
contentLayout.setOrientation(HORIZONTAL);
contentLayout.setGravity(Gravity.CENTER);
mNpLeft = new MyNumberPicker(mContext);
mNpMiddle = new MyNumberPicker(mContext);
mNpRight = new MyNumberPicker(mContext);
mUnitLeft = new TextView(mContext);
mUnitMiddle = new TextView(mContext);
mUnitRight = new TextView(mContext);
MyNumberPicker[] nps = new MyNumberPicker[]{mNpLeft, mNpMiddle, mNpRight};
for (int i = 0; i < nps.length; i++) {
nps[i].setLayoutParams(params);
nps[i].setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS);
nps[i].setOnValueChangedListener(this);
}
contentLayout.addView(mNpLeft);
contentLayout.addView(mUnitLeft);
contentLayout.addView(mNpMiddle);
contentLayout.addView(mUnitMiddle);
contentLayout.addView(mNpRight);
contentLayout.addView(mUnitRight);
this.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
this.setOrientation(VERTICAL);
this.addView(titleLayout);
this.addView(contentLayout);
}
/**
* 初始化數(shù)據(jù)和值
*/
private void initViewAndPicker() {
if (mViewCount == 1) {
this.mNpMiddle.setVisibility(GONE);
this.mNpRight.setVisibility(GONE);
this.mUnitMiddle.setVisibility(GONE);
this.mUnitRight.setVisibility(GONE);
} else if (mViewCount == 2) {
this.mNpRight.setVisibility(GONE);
this.mUnitRight.setVisibility(GONE);
}
//初始化數(shù)組值
if (mLeftValues != null && mLeftValues.length != 0) {
if (mLeftValues.length < DATA_SIZE) {
for (int i = 0; i < mLeftValues.length; i++) {
mShowingLeft[i] = mLeftValues[i];
}
for (int i = mLeftValues.length; i < DATA_SIZE; i++) {
mShowingLeft[i] = -9999;
}
} else {
for (int i = 0; i < DATA_SIZE; i++) {
mShowingLeft[i] = mLeftValues[i];
}
}
mNpLeft.setMinValue(0);
mNpLeft.setMaxValue(DATA_SIZE - 1);
if (mDefaultLeftValue != null)
updateLeftView(mDefaultLeftValue);
else
updateLeftView(mShowingLeft[0]);
}
/**
* 中間控件
*/
if (mViewCount == 2 || mViewCount == 3) {
if (mMiddleValues != null && mMiddleValues.length != 0) {
if (mMiddleValues.length < DATA_SIZE) {
for (int i = 0; i < mMiddleValues.length; i++) {
mShowingMiddle[i] = mMiddleValues[i];
}
for (int i = mMiddleValues.length; i < DATA_SIZE; i++) {
mShowingMiddle[i] = -9999;
}
} else {
for (int i = 0; i < DATA_SIZE; i++) {
mShowingMiddle[i] = mMiddleValues[i];
}
}
mNpMiddle.setMinValue(0);
mNpMiddle.setMaxValue(DATA_SIZE - 1);
if (mDefaultMiddleValue != null)
updateMiddleView(mDefaultMiddleValue);
else
updateMiddleView(mShowingMiddle[0]);
}
}
/**
* 右側(cè)控件
*/
if (mViewCount == 3) {
if (mRightValues != null && mRightValues.length != 0) {
if (mRightValues.length < DATA_SIZE) {
for (int i = 0; i < mRightValues.length; i++) {
mShowingRight[i] = mRightValues[i];
}
for (int i = mRightValues.length; i < DATA_SIZE; i++) {
mShowingRight[i] = -9999;
}
} else {
for (int i = 0; i < DATA_SIZE; i++) {
mShowingRight[i] = mRightValues[i];
}
}
mNpRight.setMinValue(0);
mNpRight.setMaxValue(DATA_SIZE - 1);
if (mDefaultRightValue != null)
updateRightView(mDefaultRightValue);
else
updateRightView(mShowingRight[0]);
}
}
}
private void updateLeftView(Object value) {
updateValue(value, 0);
}
private void updateMiddleView(Object value) {
updateValue(value, 1);
}
private void updateRightView(Object value) {
updateValue(value, 2);
}
/**
* 更新滾輪視圖
*
* @param value
* @param index
*/
private void updateValue(Object value, int index) {
String showStr[] = new String[DATA_SIZE];
MyNumberPicker picker;
Object[] showingValue;
Object[] values;
int step;
if (index == 0) {
picker = mNpLeft;
showingValue = mShowingLeft;
values = mLeftValues;
step = mLeftStep;
} else if (index == 1) {
picker = mNpMiddle;
showingValue = mShowingMiddle;
values = mMiddleValues;
step = mMiddleStep;
} else {
picker = mNpRight;
showingValue = mShowingRight;
values = mRightValues;
step = mRightStep;
}
if (values instanceof Integer[]) {
for (int i = 0; i < DATA_SIZE; i++) {
showingValue[i] = (int) value - step * (DATA_SIZE / 2 - i);
int offset = (int) values[values.length - 1] - (int) values[0] + step;
if ((int) showingValue[i] < (int) values[0]) {
showingValue[i] = (int) showingValue[i] + offset;
}
if ((int) showingValue[i] > (int) values[values.length - 1]) {
showingValue[i] = (int) showingValue[i] - offset;
}
showStr[i] = "" + showingValue[i];
}
} else {
int strIndex = 0;
for (int i = 0; i < values.length; i++) {
if (values[i].equals(value)) {
strIndex = i;
break;
}
}
for (int i = 0; i < DATA_SIZE; i++) {
int temp = strIndex - (DATA_SIZE / 2 - i);
if (temp < 0) {
temp += values.length;
}
if (temp >= values.length) {
temp -= values.length;
}
showingValue[i] = values[temp];
showStr[i] = (String) values[temp];
}
}
picker.setDisplayedValues(showStr);
picker.setValue(DATA_SIZE / 2);
picker.postInvalidate();
}
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
if (picker == mNpLeft) {
updateLeftView(mShowingLeft[newVal]);
} else if (picker == mNpMiddle) {
updateMiddleView(mShowingMiddle[newVal]);
} else if (picker == mNpRight) {
updateRightView(mShowingRight[newVal]);
}
if (mSelectedChangeListener != null) {
mSelectedChangeListener.onSelected(this, mShowingLeft[DATA_SIZE / 2], mShowingMiddle[DATA_SIZE / 2], mShowingRight[DATA_SIZE / 2]);
}
}
/**
* 設(shè)置數(shù)據(jù)--單列數(shù)據(jù)
*
* @param leftValues
* @param mDefaultLeftValue
*/
public void setValueData(Object[] leftValues, Object mDefaultLeftValue) {
this.mViewCount = 1;
this.mLeftValues = leftValues;
this.mDefaultLeftValue = mDefaultLeftValue;
initViewAndPicker();
}
/**
* 設(shè)置數(shù)據(jù)--兩列數(shù)據(jù)
*
* @param leftValues
* @param mDefaultLeftValue
* @param middleValues
* @param defaultMiddleValue
*/
public void setValueData(Object[] leftValues, Object mDefaultLeftValue, Object[] middleValues, Object defaultMiddleValue) {
this.mViewCount = 2;
this.mLeftValues = leftValues;
this.mDefaultLeftValue = mDefaultLeftValue;
this.mMiddleValues = middleValues;
this.mDefaultMiddleValue = defaultMiddleValue;
initViewAndPicker();
}
/**
* 設(shè)置數(shù)據(jù)--三列數(shù)據(jù)
*
* @param leftValues
* @param mDefaultLeftValue
* @param middleValues
* @param defaultMiddleValue
* @param rightValues
* @param defaultRightValue
*/
public void setValueData(Object[] leftValues, Object mDefaultLeftValue, Object[] middleValues, Object defaultMiddleValue, Object[] rightValues, Object defaultRightValue) {
this.mViewCount = 3;
this.mLeftValues = leftValues;
this.mDefaultLeftValue = mDefaultLeftValue;
this.mMiddleValues = middleValues;
this.mDefaultMiddleValue = defaultMiddleValue;
this.mRightValues = rightValues;
this.mDefaultRightValue = defaultRightValue;
initViewAndPicker();
}
/**
* 設(shè)置左邊數(shù)據(jù)步長(zhǎng)
*
* @param step
*/
public void setLeftStep(int step) {
this.mLeftStep = step;
initViewAndPicker();
}
/**
* 設(shè)置中間數(shù)據(jù)步長(zhǎng)
*
* @param step
*/
public void setMiddleStep(int step) {
this.mMiddleStep = step;
initViewAndPicker();
}
/**
* 設(shè)置右邊數(shù)據(jù)步長(zhǎng)
*
* @param step
*/
public void setRightStep(int step) {
this.mRightStep = step;
initViewAndPicker();
}
/**
* 設(shè)置標(biāo)題
*
* @param left
* @param middle
* @param right
*/
public void setTitle(String left, String middle, String right) {
if (left != null) {
mTitleLeft.setVisibility(VISIBLE);
mTitleLeft.setText(left);
} else {
mTitleLeft.setVisibility(GONE);
}
if (middle != null) {
mTitleMiddle.setVisibility(VISIBLE);
mTitleMiddle.setText(middle);
} else {
mTitleMiddle.setVisibility(GONE);
}
if (right != null) {
mTitleRight.setVisibility(VISIBLE);
mTitleRight.setText(right);
} else {
mTitleRight.setVisibility(GONE);
}
this.postInvalidate();
}
public void setUnitLeft(String unitLeft) {
setUnit(unitLeft, 0);
}
public void setmUnitMiddle(String unitMiddle) {
setUnit(unitMiddle, 1);
}
public void setUnitRight(String unitRight) {
setUnit(unitRight, 2);
}
private void setUnit(String unit, int index) {
TextView tvUnit;
if (index == 0) {
tvUnit = mUnitLeft;
} else if (index == 1) {
tvUnit = mUnitMiddle;
} else {
tvUnit = mUnitRight;
}
if (unit != null) {
tvUnit.setText(unit);
} else {
tvUnit.setText(" ");
}
initViewAndPicker();
}
/**
* 設(shè)置回調(diào)
*
* @param listener
*/
public void setOnSelectedChangeListener(onSelectedChangeListener listener) {
this.mSelectedChangeListener = listener;
}
/**
* dp轉(zhuǎn)px
*
* @param dp
* @return
*/
private int dip2px(int dp) {
float scale = mContext.getResources().getDisplayMetrics().density;
return (int) (scale * dp + 0.5f);
}
/**
* 回調(diào)接口
*/
public interface onSelectedChangeListener {
void onSelected(PickValueView view, Object leftValue, Object middleValue, Object rightValue);
}
}
關(guān)于NumberPicker
默認(rèn)的NumberPicker往往字體顏色、分割線顏色等都是跟隨系統(tǒng),不能改變,考慮到可能比較丑或者有其他需求,所以自定義的NumberPicker,通過反射的方式更改里面的一些屬性,代碼如下:
package com.example.moore.picktimeview.widget;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.NumberPicker;
import java.lang.reflect.Field;
/**
* Created by Moore on 2016/10/20.
*/
public class MyNumberPicker extends NumberPicker {
private static int mTextSize = 16;
private static int mTextColor = 0x000000;
private static int mDividerColor = 0xFFFF00;
public MyNumberPicker(Context context) {
super(context);
setNumberPickerDividerColor();
}
public MyNumberPicker(Context context, AttributeSet attrs) {
super(context, attrs);
setNumberPickerDividerColor();
}
public MyNumberPicker(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setNumberPickerDividerColor();
}
@Override
public void addView(View child) {
super.addView(child);
updateView(child);
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
updateView(child);
}
@Override
public void addView(View child, ViewGroup.LayoutParams params) {
super.addView(child, params);
updateView(child);
}
private void updateView(View view) {
if (view instanceof EditText) {
// ((EditText) view).setTextSize(mTextSize);
((EditText) view).setTextSize(17);
// ((EditText) view).setTextColor(mTextColor);
((EditText) view).setTextColor(Color.parseColor("#6495ED"));
}
}
private void setNumberPickerDividerColor() {
Field[] pickerFields = NumberPicker.class.getDeclaredFields();
/**
* 設(shè)置分割線顏色
*/
for (Field pf : pickerFields) {
if (pf.getName().equals("mSelectionDivider")) {
pf.setAccessible(true);
try {
// pf.set(this, new ColorDrawable(mDividerColor));
pf.set(this, new ColorDrawable(Color.parseColor("#C4C4C4")));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
break;
}
}
/**
* 設(shè)置分割線高度
*/
for (Field pf : pickerFields) {
if (pf.getName().equals("mSelectionDividerHeight")) {
pf.setAccessible(true);
try {
pf.set(this, 2);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
break;
}
}
for (Field pf : pickerFields) {
if (pf.getName().equals("mSelectorElementHeight")) {
pf.setAccessible(true);
try {
pf.set(this, 2);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
break;
}
}
}
public void setDividerColor(int color) {
this.mDividerColor = color;
// this.postInvalidate();
}
public void setTextColor(int color) {
this.mTextColor = color;
// this.postInvalidate();
}
public void setTextSize(int textSize) {
this.mTextSize = textSize;
// this.postInvalidate();
}
}
完整Demo可前往github查看與下載,地址:https://github.com/lizebinbin/PickTimeView.git 謝謝!
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android自定義FloatingText仿點(diǎn)贊+1特效
這篇文章主要為大家詳細(xì)介紹了Android自定義FloatingText仿點(diǎn)贊+1特效,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03
android開發(fā)之調(diào)用手機(jī)的攝像頭使用MediaRecorder錄像并播放
我們玩玩手機(jī)的錄像功能吧;今天做個(gè)調(diào)用手機(jī)的攝像頭使用MediaRecorder錄像并播放的DEMO,源碼很詳細(xì),感興趣的朋友可以了解下,希望本文對(duì)你有幫助2013-01-01
詳解Android的Splash啟動(dòng)圖的兩種動(dòng)態(tài)切換方式
本篇文章主要介紹了詳解Android的Splash啟動(dòng)圖的兩種動(dòng)態(tài)切換方式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
Android使用google breakpad捕獲分析native cash
這篇文章主要介紹了Android使用google breakpad捕獲分析native cash 的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04
Android編程使用android-support-design實(shí)現(xiàn)MD風(fēng)格對(duì)話框功能示例
這篇文章主要介紹了Android編程使用android-support-design實(shí)現(xiàn)MD風(fēng)格對(duì)話框功能,涉及Android對(duì)話框、視圖、布局相關(guān)操作技巧,需要的朋友可以參考下2017-01-01
SurfaceView播放視頻發(fā)送彈幕并實(shí)現(xiàn)滾動(dòng)歌詞
這篇文章主要為大家詳細(xì)介紹了SurfaceView播放視頻發(fā)送彈幕并實(shí)現(xiàn)滾動(dòng)歌詞,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11

