2012年1月2日月曜日

ColorPicker の Action Provider を作った

色選択するための Action Provider を作りました。

HSV の領域をタッチして色を変えます。 SとVはそれぞれの現在値に応じて領域の色が変わるようになっています。



いつものように github にもおきましたー。
yanzm/ColorPickerActionProvider - GitHub - public class MainActivity extends Activity { private int mSelectedColor = Color.BLACK; @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.menu, menu); MenuItem item = menu.findItem(R.id.menu_color_picker); HsvColorActionProvider actionProvider = (HsvColorActionProvider) item.getActionProvider(); actionProvider.setOnColorChangedListener(new HsvColorActionProvider.OnColorChangedListener() { @Override public void onColorChanged(int color) { View v = findViewById(android.R.id.content); v.setBackgroundColor(color); } @Override public void onColorSelected(int color) { mSelectedColor = color; View v = findViewById(android.R.id.content); v.setBackgroundColor(color); } @Override public void onCanceled() { View v = findViewById(android.R.id.content); v.setBackgroundColor(mSelectedColor); } }); return true; } }

public class HsvColorActionProvider extends ActionProvider { public interface OnColorChangedListener { public void onColorChanged(int color); public void onColorSelected(int color); public void onCanceled(); } private OnColorChangedListener mListener; private Context mContext; private LayoutInflater mLayoutInflater; private PopupWindow mPopupWindow; private HsvColorPickerView mColorPicker; private int mInitialColor; public HsvColorActionProvider(Context context) { super(context); mContext = context; mInitialColor = Color.HSVToColor(new float[] { 180, 0.7f, 0.8f }); mLayoutInflater = LayoutInflater.from(context); View v = mLayoutInflater.inflate(R.layout.color_popup, null, false); mColorPicker = (HsvColorPickerView) v.findViewById(R.id.color_picker); mColorPicker.showPreview(true); mColorPicker.setIniticalColor(mInitialColor); mColorPicker.setOnColorChangedListener(new HsvColorPickerView.OnColorChangedListener() { @Override public void onColorChanged(int color, float[] hsv) { if (mListener != null) { mListener.onColorChanged(color); } } }); v.findViewById(R.id.cancel_btn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mPopupWindow.dismiss(); if (mListener != null) { mListener.onCanceled(); } } }); v.findViewById(R.id.ok_btn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mInitialColor = mColorPicker.getCurrentColor(); if (mListener != null) { mListener.onColorSelected(mInitialColor); } mPopupWindow.dismiss(); } }); mPopupWindow = new PopupWindow(v); mPopupWindow.setBackgroundDrawable(mContext.getResources().getDrawable(R.drawable.panel_bg)); mPopupWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT); mPopupWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT); } public void setOnColorChangedListener(OnColorChangedListener l) { mListener = l; } @Override public View onCreateActionView() { LayoutInflater layoutInflater = LayoutInflater.from(mContext); final View actionItem = layoutInflater.inflate(R.layout.color_action_provider, null); ImageButton button = (ImageButton) actionItem.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (!mPopupWindow.isShowing()) { mColorPicker.setIniticalColor(mInitialColor); mPopupWindow.showAsDropDown(actionItem); } else { mPopupWindow.dismiss(); } } }); return actionItem; } }

public class HsvColorPickerView extends View { public interface OnColorChangedListener { void onColorChanged(int color, float[] hsv); } public void setOnColorChangedListener(OnColorChangedListener l) { mListener = l; } /** * 初期カラーをセットする * * @param color */ public void setIniticalColor(int color) { mCurrentColor = color; Color.colorToHSV(mCurrentColor, mCurrentHSV); invalidate(); } /** * 現在の色を返す * * @return */ public int getCurrentColor() { return mCurrentColor; } /** * プレビューを表示するかどうか * * @param show */ public void showPreview(boolean show) { mIsShowPreview = show; updateRectArea(); } /** * 色領域の幅をセットする * * @param width */ public void setRectWidth(int width) { mRectWidth = width; updateRectArea(); } /** * 色領域の高さをセットする * * @param height */ public void setRectHeight(int height) { mRectHeight = height; updateRectArea(); } /** * 色領域間のギャップをセットする * * @param gap */ public void setRectGap(int gap) { mRectGap = gap; updateRectArea(); } private static final int RECT_WIDTH = 400; private static final int RECT_HEIGHT = 80; private static final int RECT_GAP = 20; private boolean mIsShowPreview = true; private int mRectWidth = RECT_WIDTH; private int mRectHeight = RECT_HEIGHT; private int mRectGap = RECT_GAP; private OnColorChangedListener mListener; private int mCurrentColor = Color.RED; private float[] mCurrentHSV = new float[3]; private Shader mHueShader; private Shader mSaturationShader; private Shader mValueShader; private Paint mHuePaint; private Paint mValuePaint; private Paint mSaturationPaint; private Paint mPreviewPaint; private Paint mLinePaint; private Rect mHueRect; private Rect mSaturationRect; private Rect mValueRect; private Rect mPreviewRect; int[] mHueList; public HsvColorPickerView(Context c) { super(c); init(); } public HsvColorPickerView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { Color.colorToHSV(mCurrentColor, mCurrentHSV); mHueList = new int[10]; float hue = 0; for (int i = 0; i < 10; i++) { mHueList[i] = setHSVColor(hue, 255, 255); hue += 36; } mHuePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mHuePaint.setStyle(Paint.Style.FILL); mHuePaint.setStrokeWidth(2); mValuePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mValuePaint.setStyle(Paint.Style.FILL); mValuePaint.setStrokeWidth(2); mSaturationPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mSaturationPaint.setStyle(Paint.Style.FILL); mSaturationPaint.setStrokeWidth(2); mPreviewPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPreviewPaint.setStyle(Paint.Style.FILL); mPreviewPaint.setStrokeWidth(5); mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mLinePaint.setStyle(Paint.Style.FILL); mLinePaint.setStrokeWidth(5); mLinePaint.setColor(Color.BLACK); updateRectArea(); } private void updateRectArea() { mHueShader = new LinearGradient(0, 0, mRectWidth, 0, mHueList, null, Shader.TileMode.CLAMP); mHuePaint.setShader(mHueShader); if (mIsShowPreview) { mPreviewRect = new Rect(0, 0, mRectWidth, mRectHeight); mHueRect = new Rect(0, mRectHeight + mRectGap, mRectWidth, mRectHeight * 2 + mRectGap); mSaturationRect = new Rect(0, mRectHeight * 2 + mRectGap * 2, mRectWidth, mRectHeight * 3 + mRectGap * 2); mValueRect = new Rect(0, mRectHeight * 3 + mRectGap * 3, mRectWidth, mRectHeight * 4 + mRectGap * 3); } else { mHueRect = new Rect(0, 0, mRectWidth, mRectHeight); mSaturationRect = new Rect(0, mRectHeight + mRectGap, mRectWidth, mRectHeight * 2 + mRectGap); mValueRect = new Rect(0, mRectHeight * 2 + mRectGap * 2, mRectWidth, mRectHeight * 3 + mRectGap * 2); } } @Override protected void onDraw(Canvas canvas) { // Hue canvas.drawRect(mHueRect, mHuePaint); canvas.drawLine(mCurrentHSV[0] * mRectWidth / 360, mHueRect.top, mCurrentHSV[0] * mRectWidth / 360, mHueRect.bottom, mLinePaint); // Saturation int[] mSaturationList = new int[10]; float saturation = 0; for (int i = 0; i < 10; i++) { mSaturationList[i] = setHSVColor(mCurrentHSV[0], saturation, mCurrentHSV[2]); saturation += 0.1; } mSaturationShader = new LinearGradient(0, 0, mRectWidth, 0, mSaturationList, null, Shader.TileMode.CLAMP); mSaturationPaint.setShader(mSaturationShader); canvas.drawRect(mSaturationRect, mSaturationPaint); canvas.drawLine(mCurrentHSV[1] * mRectWidth, mSaturationRect.top, mCurrentHSV[1] * mRectWidth, mSaturationRect.bottom, mLinePaint); // Value int[] mValueList = new int[10]; float value = 0; for (int i = 0; i < 10; i++) { mValueList[i] = setHSVColor(mCurrentHSV[0], mCurrentHSV[1], value); value += 0.1; } mValueShader = new LinearGradient(0, 0, mRectWidth, 0, mValueList, null, Shader.TileMode.CLAMP); mValuePaint.setShader(mValueShader); canvas.drawRect(mValueRect, mValuePaint); canvas.drawLine(mCurrentHSV[2] * mRectWidth, mValueRect.top, mCurrentHSV[2] * mRectWidth, mValueRect.bottom, mLinePaint); if (mIsShowPreview) { // Preview mPreviewPaint.setColor(mCurrentColor); canvas.drawRect(mPreviewRect, mPreviewPaint); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mIsShowPreview) { setMeasuredDimension(mRectWidth, mRectHeight * 4 + mRectGap * 3); } else { setMeasuredDimension(mRectWidth, mRectHeight * 3 + mRectGap * 2); } } private int setHSVColor(float hue, float saturation, float value) { float[] hsv = new float[3]; hsv[0] = Math.max(0, Math.min(359, hue)); hsv[1] = Math.max(0, Math.min(1, saturation)); hsv[2] = Math.max(0, Math.min(1, value)); return Color.HSVToColor(hsv); } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); boolean inHue = mHueRect.contains((int) x, (int) y); boolean inSaturation = mSaturationRect.contains((int) x, (int) y); boolean inValue = mValueRect.contains((int) x, (int) y); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: if (inHue) { float unit = x / mRectWidth; mCurrentHSV[0] = Math.max(0, Math.min(unit * 360, 359)); updateCurrentColor(); } else if (inSaturation) { mCurrentHSV[1] = Math.max(0, Math.min(x / mRectWidth, 1)); updateCurrentColor(); } else if (inValue) { mCurrentHSV[2] = Math.max(0, Math.min(x / mRectWidth, 1)); updateCurrentColor(); } break; } return true; } private void updateCurrentColor() { mCurrentColor = Color.HSVToColor(mCurrentHSV); if (mListener != null) { mListener.onColorChanged(mCurrentColor, mCurrentHSV); } invalidate(); } }

1 件のコメント:

  1. 初めまして!まだまだ始めたばっかりですが、趣味でAndroidアプリの開発をやっているWTNBといいます。突然のコメントですみませんw 開発を始めた当初からyanzmさんのブログで勉強させて頂いています。素人の僕にも非常に分かり易くてホント助かっています!ありがとうございます!
    そしてこの度、非常にクオリティの低くて申し訳ないのですがw yanzmさんのブログのおかげで電卓アプリを公開することが出来ました→https://market.android.com/details?id=watanabe111.systema&feature=search_result#?t=W251bGwsMSwxLDEsIndhdGFuYWJlMTExLnN5c3RlbWEiXQ.. これからもyanzmさんのブログを参考にさせて頂いて、もっともっとアプリを作っていけたらなと思ってます。ホント毎回丁寧な説明記事をありがとうございます。

    返信削除

'},ClipboardSwf:null,Version:'1.5.1'}};dp.SyntaxHighlighter=dp.sh;dp.sh.Toolbar.Commands={ExpandSource:{label:'+ expand source',check:function(highlighter){return highlighter.collapse;},func:function(sender,highlighter) {sender.parentNode.removeChild(sender);highlighter.div.className=highlighter.div.className.replace('collapsed','');}},ViewSource:{label:'view plain',func:function(sender,highlighter) {var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/'+code+'');wnd.document.close();}},CopyToClipboard:{label:'copy to clipboard',check:function(){return window.clipboardData!=null||dp.sh.ClipboardSwf!=null;},func:function(sender,highlighter) {var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');if(window.clipboardData) {window.clipboardData.setData('text',code);} else if(dp.sh.ClipboardSwf!=null) {var flashcopier=highlighter.flashCopier;if(flashcopier==null) {flashcopier=document.createElement('div');highlighter.flashCopier=flashcopier;highlighter.div.appendChild(flashcopier);} flashcopier.innerHTML='';} alert('The code is in your clipboard now');}},PrintSource:{label:'print',func:function(sender,highlighter) {var iframe=document.createElement('IFRAME');var doc=null;iframe.style.cssText='position:absolute;width:0px;height:0px;left:-500px;top:-500px;';document.body.appendChild(iframe);doc=iframe.contentWindow.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write('

'+highlighter.div.innerHTML+'

');doc.close();iframe.contentWindow.focus();iframe.contentWindow.print();alert('Printing...');document.body.removeChild(iframe);}},About:{label:'?',func:function(highlighter) {var wnd=window.open('','_blank','dialog,width=300,height=150,scrollbars=0');var doc=wnd.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write(dp.sh.Strings.AboutDialog.replace('{V}',dp.sh.Version));doc.close();wnd.focus();}}};dp.sh.Toolbar.Create=function(highlighter) {var div=document.createElement('DIV');div.className='tools';for(var name in dp.sh.Toolbar.Commands) {var cmd=dp.sh.Toolbar.Commands[name];if(cmd.check!=null&&!cmd.check(highlighter)) continue;div.innerHTML+=''+cmd.label+'';} return div;} dp.sh.Toolbar.Command=function(name,sender) {var n=sender;while(n!=null&&n.className.indexOf('dp-highlighter')==-1) n=n.parentNode;if(n!=null) dp.sh.Toolbar.Commands[name].func(sender,n.highlighter);} dp.sh.Utils.CopyStyles=function(destDoc,sourceDoc) {var links=sourceDoc.getElementsByTagName('link');for(var i=0;i');} dp.sh.Utils.FixForBlogger=function(str) {return(dp.sh.isBloggerMode==true)?str.replace(/
|<br\s*\/?>/gi,''):str;} dp.sh.RegexLib={MultiLineCComments:new RegExp('/\\*[\\s\\S]*?\\*/','gm'),SingleLineCComments:new RegExp('//.*$','gm'),SingleLinePerlComments:new RegExp('#.*$','gm'),DoubleQuotedString:new RegExp('"(?:\\.|(\\\\\\")|[^\\""\\n])*"','g'),SingleQuotedString:new RegExp("'(?:\\.|(\\\\\\')|[^\\''\\n])*'",'g')};dp.sh.Match=function(value,index,css) {this.value=value;this.index=index;this.length=value.length;this.css=css;} dp.sh.Highlighter=function() {this.noGutter=false;this.addControls=true;this.collapse=false;this.tabsToSpaces=true;this.wrapColumn=80;this.showColumns=true;} dp.sh.Highlighter.SortCallback=function(m1,m2) {if(m1.indexm2.index) return 1;else {if(m1.lengthm2.length) return 1;} return 0;} dp.sh.Highlighter.prototype.CreateElement=function(name) {var result=document.createElement(name);result.highlighter=this;return result;} dp.sh.Highlighter.prototype.GetMatches=function(regex,css) {var index=0;var match=null;while((match=regex.exec(this.code))!=null) this.matches[this.matches.length]=new dp.sh.Match(match[0],match.index,css);} dp.sh.Highlighter.prototype.AddBit=function(str,css) {if(str==null||str.length==0) return;var span=this.CreateElement('SPAN');str=str.replace(/ /g,' ');str=str.replace(/');if(css!=null) {if((/br/gi).test(str)) {var lines=str.split(' 
');for(var i=0;ic.index)&&(match.index/gi,'\n');var lines=html.split('\n');if(this.addControls==true) this.bar.appendChild(dp.sh.Toolbar.Create(this));if(this.showColumns) {var div=this.CreateElement('div');var columns=this.CreateElement('div');var showEvery=10;var i=1;while(i<=150) {if(i%showEvery==0) {div.innerHTML+=i;i+=(i+'').length;} else {div.innerHTML+='·';i++;}} columns.className='columns';columns.appendChild(div);this.bar.appendChild(columns);} for(var i=0,lineIndex=this.firstLine;i0;i++) {if(Trim(lines[i]).length==0) continue;var matches=regex.exec(lines[i]);if(matches!=null&&matches.length>0) min=Math.min(matches[0].length,min);} if(min>0) for(var i=0;i

Blogger Syntax Highliter

Version: {V}

http://www.dreamprojections.com/syntaxhighlighter

©2004-2007 Alex Gorbatchev.

'},ClipboardSwf:null,Version:'1.5.1'}};dp.SyntaxHighlighter=dp.sh;dp.sh.Toolbar.Commands={ExpandSource:{label:'+ expand source',check:function(highlighter){return highlighter.collapse;},func:function(sender,highlighter) {sender.parentNode.removeChild(sender);highlighter.div.className=highlighter.div.className.replace('collapsed','');}},ViewSource:{label:'view plain',func:function(sender,highlighter) {var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/'+code+'');wnd.document.close();}},CopyToClipboard:{label:'copy to clipboard',check:function(){return window.clipboardData!=null||dp.sh.ClipboardSwf!=null;},func:function(sender,highlighter) {var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');if(window.clipboardData) {window.clipboardData.setData('text',code);} else if(dp.sh.ClipboardSwf!=null) {var flashcopier=highlighter.flashCopier;if(flashcopier==null) {flashcopier=document.createElement('div');highlighter.flashCopier=flashcopier;highlighter.div.appendChild(flashcopier);} flashcopier.innerHTML='';} alert('The code is in your clipboard now');}},PrintSource:{label:'print',func:function(sender,highlighter) {var iframe=document.createElement('IFRAME');var doc=null;iframe.style.cssText='position:absolute;width:0px;height:0px;left:-500px;top:-500px;';document.body.appendChild(iframe);doc=iframe.contentWindow.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write('

'+highlighter.div.innerHTML+'

');doc.close();iframe.contentWindow.focus();iframe.contentWindow.print();alert('Printing...');document.body.removeChild(iframe);}},About:{label:'?',func:function(highlighter) {var wnd=window.open('','_blank','dialog,width=300,height=150,scrollbars=0');var doc=wnd.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write(dp.sh.Strings.AboutDialog.replace('{V}',dp.sh.Version));doc.close();wnd.focus();}}};dp.sh.Toolbar.Create=function(highlighter) {var div=document.createElement('DIV');div.className='tools';for(var name in dp.sh.Toolbar.Commands) {var cmd=dp.sh.Toolbar.Commands[name];if(cmd.check!=null&&!cmd.check(highlighter)) continue;div.innerHTML+=''+cmd.label+'';} return div;} dp.sh.Toolbar.Command=function(name,sender) {var n=sender;while(n!=null&&n.className.indexOf('dp-highlighter')==-1) n=n.parentNode;if(n!=null) dp.sh.Toolbar.Commands[name].func(sender,n.highlighter);} dp.sh.Utils.CopyStyles=function(destDoc,sourceDoc) {var links=sourceDoc.getElementsByTagName('link');for(var i=0;i');} dp.sh.Utils.FixForBlogger=function(str) {return(dp.sh.isBloggerMode==true)?str.replace(/
|<br\s*\/?>/gi,'\n'):str;} dp.sh.RegexLib={MultiLineCComments:new RegExp('/\\*[\\s\\S]*?\\*/','gm'),SingleLineCComments:new RegExp('//.*$','gm'),SingleLinePerlComments:new RegExp('#.*$','gm'),DoubleQuotedString:new RegExp('"(?:\\.|(\\\\\\")|[^\\""\\n])*"','g'),SingleQuotedString:new RegExp("'(?:\\.|(\\\\\\')|[^\\''\\n])*'",'g')};dp.sh.Match=function(value,index,css) {this.value=value;this.index=index;this.length=value.length;this.css=css;} dp.sh.Highlighter=function() {this.noGutter=false;this.addControls=true;this.collapse=false;this.tabsToSpaces=true;this.wrapColumn=80;this.showColumns=true;} dp.sh.Highlighter.SortCallback=function(m1,m2) {if(m1.indexm2.index) return 1;else {if(m1.lengthm2.length) return 1;} return 0;} dp.sh.Highlighter.prototype.CreateElement=function(name) {var result=document.createElement(name);result.highlighter=this;return result;} dp.sh.Highlighter.prototype.GetMatches=function(regex,css) {var index=0;var match=null;while((match=regex.exec(this.code))!=null) this.matches[this.matches.length]=new dp.sh.Match(match[0],match.index,css);} dp.sh.Highlighter.prototype.AddBit=function(str,css) {if(str==null||str.length==0) return;var span=this.CreateElement('SPAN');str=str.replace(/ /g,' ');str=str.replace(/');if(css!=null) {if((/br/gi).test(str)) {var lines=str.split(' 
');for(var i=0;ic.index)&&(match.index/gi,'\n');var lines=html.split('\n');if(this.addControls==true) this.bar.appendChild(dp.sh.Toolbar.Create(this));if(this.showColumns) {var div=this.CreateElement('div');var columns=this.CreateElement('div');var showEvery=10;var i=1;while(i<=150) {if(i%showEvery==0) {div.innerHTML+=i;i+=(i+'').length;} else {div.innerHTML+='·';i++;}} columns.className='columns';columns.appendChild(div);this.bar.appendChild(columns);} for(var i=0,lineIndex=this.firstLine;i0;i++) {if(Trim(lines[i]).length==0) continue;var matches=regex.exec(lines[i]);if(matches!=null&&matches.length>0) min=Math.min(matches[0].length,min);} if(min>0) for(var i=0;i

ページビューの合計