前段时间客户需求,要加几个按钮,包括清理缓存,关于,设置,定位等。可是界面已经做好了,再重新布局界面,很麻烦。所以做了这么个小Button。在此分享,供大家学习。下面是几张截图,动画效果没工具保存,是依次展开的。文末附有源码下载链接。
首先上自定义布局文件:ComposerLayout.java
package com.example.button; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.AttributeSet; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; @SuppressLint("ViewConstructor") public class ComposerLayout extends RelativeLayout { public static byte RIGHTBOTTOM = 1, CENTERBOTTOM = 2, LEFTBOTTOM = 3, LEFTCENTER = 4, LEFTTOP = 5, CENTERTOP = 6, RIGHTTOP = 7, RIGHTCENTER = 8; private boolean hasInit = false; private boolean areButtonsShowing = false; private Context mycontext; private ImageView cross; private RelativeLayout rlButton; private Animations myani; private LinearLayout[] llayouts; private int duretime = 300; public ComposerLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.mycontext = context; } public ComposerLayout(Context context, AttributeSet attrs) { super(context, attrs); this.mycontext = context; } public ComposerLayout(Context context) { super(context); this.mycontext = context; } /** * 初始化 * * @param imgResId * 子按钮图片drawable的id * @param showhideButtonId * 主按鈕drawable的id * @param crossId * 主按鈕上面十字片drawable的id * @param pCode * 位置代碼,例如“右上角”ALIGN_PARENT_BOTTOM|ALIGN_PARENT_RIGHT * @param radius * * @param durationMillis * 动画耗时 */ public void init(int[] imgResId, int showhideButtonId, int crossId, byte pCode, int radius, final int durationMillis) { duretime = durationMillis; int align1 = 12, align2 = 14; if (pCode == RIGHTBOTTOM) { // 右下角 align1 = ALIGN_PARENT_RIGHT; align2 = ALIGN_PARENT_BOTTOM; } else if (pCode == CENTERBOTTOM) {// 中下 align1 = CENTER_HORIZONTAL; align2 = ALIGN_PARENT_BOTTOM; } else if (pCode == LEFTBOTTOM) { // 左下角 align1 = ALIGN_PARENT_LEFT; align2 = ALIGN_PARENT_BOTTOM; } else if (pCode == LEFTCENTER) { // 左中 align1 = ALIGN_PARENT_LEFT; align2 = CENTER_VERTICAL; } else if (pCode == LEFTTOP) { // 左上角 align1 = ALIGN_PARENT_LEFT; align2 = ALIGN_PARENT_TOP; } else if (pCode == CENTERTOP) { // 中上 align1 = CENTER_HORIZONTAL; align2 = ALIGN_PARENT_TOP; } else if (pCode == RIGHTTOP) { // 右上角 align1 = ALIGN_PARENT_RIGHT; align2 = ALIGN_PARENT_TOP; } else if (pCode == RIGHTCENTER) { // 右中 align1 = ALIGN_PARENT_RIGHT; align2 = CENTER_VERTICAL; } // 处理半径 RelativeLayout.LayoutParams thislps = (LayoutParams) this .getLayoutParams(); Bitmap mBottom = BitmapFactory.decodeResource(mycontext.getResources(), imgResId[0]); if (pCode == CENTERBOTTOM || pCode == CENTERTOP) { if (thislps.width != -1 && thislps.width != -2 && thislps.width < (radius + mBottom.getWidth() + radius * 0.1) * 2) { thislps.width = (int) ((radius * 1.1 + mBottom.getWidth()) * 2); } } else { if (thislps.width != -1 && thislps.width != -2 && thislps.width < radius + mBottom.getWidth() + radius * 0.1) { thislps.width = (int) (radius * 1.1 + mBottom.getWidth()); } } if (pCode == LEFTCENTER || pCode == RIGHTCENTER) { if (thislps.height != -1 && thislps.height != -2 && thislps.height < (radius + mBottom.getHeight() + radius * 0.1) * 2) { thislps.width = (int) ((radius * 1.1 + mBottom.getHeight()) * 2); } } else { if (thislps.height != -1 && thislps.height != -2 && thislps.height < radius + mBottom.getHeight() + radius * 0.1) { thislps.height = (int) (radius * 1.1 + mBottom.getHeight()); } } this.setLayoutParams(thislps); RelativeLayout rl1 = new RelativeLayout(mycontext);// 包含若干子按鈕 rlButton = new RelativeLayout(mycontext); // 主按扭 llayouts = new LinearLayout[imgResId.length]; // N个子按鈕 for (int i = 0; i < imgResId.length; i++) { ImageView img = new ImageView(mycontext);// 子按扭圖片 img.setImageResource(imgResId[i]); LinearLayout.LayoutParams llps = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); img.setLayoutParams(llps); llayouts[i] = new LinearLayout(mycontext);// 子按鈕 llayouts[i].setId(100 + i);// 随便设个id,方便onclick的时候识别。随便设,如果发现同其他控件沖突就自行改一下。 llayouts[i].addView(img); RelativeLayout.LayoutParams rlps = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); rlps.alignWithParent = true; rlps.addRule(align1, RelativeLayout.TRUE); rlps.addRule(align2, RelativeLayout.TRUE); llayouts[i].setLayoutParams(rlps); llayouts[i].setVisibility(View.INVISIBLE);// 此处不能为GONE rl1.addView(llayouts[i]); } RelativeLayout.LayoutParams rlps1 = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT); rlps1.alignWithParent = true; rlps1.addRule(align1, RelativeLayout.TRUE); rlps1.addRule(align2, RelativeLayout.TRUE); rl1.setLayoutParams(rlps1); RelativeLayout.LayoutParams buttonlps = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); buttonlps.alignWithParent = true; buttonlps.addRule(align1, RelativeLayout.TRUE); buttonlps.addRule(align2, RelativeLayout.TRUE); rlButton.setLayoutParams(buttonlps); rlButton.setBackgroundResource(showhideButtonId); cross = new ImageView(mycontext); cross.setImageResource(crossId); RelativeLayout.LayoutParams crosslps = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); crosslps.alignWithParent = true; crosslps.addRule(CENTER_IN_PARENT, RelativeLayout.TRUE); cross.setLayoutParams(crosslps); rlButton.addView(cross); myani = new Animations(rl1, pCode, radius); rlButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (areButtonsShowing) { myani.startAnimationsOut(duretime); cross.startAnimation(Animations.getRotateAnimation(-270, 0, duretime)); } else { myani.startAnimationsIn(duretime); cross.startAnimation(Animations.getRotateAnimation(0, -270, duretime)); } areButtonsShowing = !areButtonsShowing; } }); cross.startAnimation(Animations.getRotateAnimation(0, 360, 200)); this.addView(rl1); this.addView(rlButton); hasInit = true; } public void collapse() { myani.startAnimationsOut(duretime); cross.startAnimation(Animations.getRotateAnimation(-270, 0, duretime)); areButtonsShowing = false; } public void expand() { myani.startAnimationsIn(duretime); cross.startAnimation(Animations.getRotateAnimation(0, -270, duretime)); areButtonsShowing = true; } public boolean isInit() { return hasInit; } public boolean isShow() { return areButtonsShowing; } /** * 设置各子按钮OnClick事件 */ public void setButtonsOnClickListener(final OnClickListener l) { if (llayouts != null) { for (int i = 0; i < llayouts.length; i++) { if (llayouts[i] != null) llayouts[i].setOnClickListener(new OnClickListener() { @Override public void onClick(final View view) { //此处添加其他事件比如按钮增大或者缩回菜单 collapse(); l.onClick(view); } }); } } } }这里自定义了一个BaseActivity,使用BaseActivity的好处不用我说了吧:
package com.example.button; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; public abstract class BaseActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setView(); initView(); setListener(); initData(); } @Override protected void onResume() { super.onResume(); } @Override protected void onPause() { super.onPause(); } /** * 设置布局文件 */ public abstract void setView(); /** * 初始化布局文件中的控件 */ public abstract void initView(); /** * 设置控件的监听 */ public abstract void setListener(); private void initData() { String appID = "wx88818f8c48a95eb4"; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); } }动画设置类,Animations,这里用了一个开源动画库nineoldandroids.jar。下载文末原代码中有
package com.example.button; import static com.nineoldandroids.view.ViewPropertyAnimator.animate; import java.util.ArrayList; import java.util.List; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.RotateAnimation; import android.widget.LinearLayout; import com.nineoldandroids.animation.Animator; import com.nineoldandroids.animation.Animator.AnimatorListener; import com.nineoldandroids.view.ViewPropertyAnimator; public class Animations { public final int R; // 半径 public static byte RIGHTBOTTOM = 1, CENTERBOTTOM = 2, LEFTBOTTOM = 3, LEFTCENTER = 4, LEFTTOP = 5, CENTERTOP = 6, RIGHTTOP = 7, RIGHTCENTER = 8; private int pc; // 位置代号 private ViewGroup clayout; // 父layout private final int amount; // 有幾多個按鈕 private double fullangle = 180.0;// 在幾大嘅角度內排佈 private byte xOri = 1, yOri = 1; // x、y值嘅方向,即系向上還是向下 private boolean isOpen = false;// 记录是已经打开还是关闭 private List<ViewPropertyAnimator> viewAnimators = new ArrayList<ViewPropertyAnimator>(); /** * 構造函數 * * @param comlayout * 包裹彈出按鈕嘅layout * @param poscode * 位置代號,分別對應RIGHTBOTTOM、CENTERBOTTOM、LEFTBOTTOM、LEFTCENTER、 * LEFTTOP、CENTERTOP、RIGHTTOP、RIGHTCENTER * @param radius * 半徑 */ public Animations(ViewGroup comlayout, int poscode, int radius) { this.pc = poscode; this.clayout = comlayout; this.amount = clayout.getChildCount(); this.R = radius; // 初始化动画,每个view对应一个animator for (int i = 0; i < amount; i++) { View childAt = clayout.getChildAt(i); ViewPropertyAnimator anim = animate(childAt); viewAnimators.add(anim); } if (poscode == RIGHTBOTTOM) { // 右下角 fullangle = 90; xOri = -1; yOri = -1; } else if (poscode == CENTERBOTTOM) {// 中下 fullangle = 180; xOri = -1; yOri = -1; } else if (poscode == LEFTBOTTOM) { // 左下角 fullangle = 90; xOri = 1; yOri = -1; } else if (poscode == LEFTCENTER) { // 左中 fullangle = 180; xOri = 1; yOri = -1; } else if (poscode == LEFTTOP) { // 左上角 fullangle = 90; xOri = 1; yOri = 1; } else if (poscode == CENTERTOP) { // 中上 fullangle = 180; xOri = -1; yOri = 1; } else if (poscode == RIGHTTOP) { // 右上角 fullangle = 90; xOri = -1; yOri = 1; } else if (poscode == RIGHTCENTER) { // 右中 fullangle = 180; xOri = -1; yOri = -1; } } private class AnimListener implements AnimatorListener { private View target; public AnimListener(View _target) { target = _target; } @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { if (!isOpen) { target.setVisibility(View.INVISIBLE); } } @Override public void onAnimationCancel(Animator animation) { // TODO Auto-generated method stub } @Override public void onAnimationRepeat(Animator animation) { // TODO Auto-generated method stub } } <pre name="code" class="java"> /** * 开 */public void startAnimationsIn(int durationMillis) {isOpen = true;for (int i = 0; i < clayout.getChildCount(); i++) {final LinearLayout inoutimagebutton = (LinearLayout) clayout.getChildAt(i);double offangle = fullangle / (amount - 1);final double deltaY, deltaX;if (pc == LEFTCENTER || pc == RIGHTCENTER) {deltaX = Math.sin(offangle * i * Math.PI / 180) * R;deltaY = Math.cos(offangle * i * Math.PI / 180) * R;} else {deltaY = Math.sin(offangle * i * Math.PI / 180) * R;deltaX = Math.cos(offangle * i * Math.PI / 180) * R;}ViewPropertyAnimator viewPropertyAnimator = viewAnimators.get(i);viewPropertyAnimator.setListener(null);inoutimagebutton.setVisibility(View.VISIBLE);viewPropertyAnimator.x((float) (inoutimagebutton.getLeft() + xOri * deltaX)).y((float) (inoutimagebutton.getTop() + yOri * deltaY));}}/** * 收 */public void startAnimationsOut(int durationMillis) {isOpen = false;for (int i = 0; i < clayout.getChildCount(); i++) {final LinearLayout inoutimagebutton = (LinearLayout) clayout.getChildAt(i);ViewPropertyAnimator viewPropertyAnimator = viewAnimators.get(i);viewPropertyAnimator.setListener(null);viewPropertyAnimator.x((float) inoutimagebutton.getLeft()).y((float) inoutimagebutton.getTop());viewPropertyAnimator.setListener(new AnimListener(inoutimagebutton));}}public int getPosCode() {return this.pc;}/** * 自转函数 * * @param fromDegrees * 从多少度 * @param toDegrees * 到多少度 * @param durationMillis * m */public static Animation getRotateAnimation(float fromDegrees,float toDegrees, int durationMillis) {RotateAnimation rotate = new RotateAnimation(fromDegrees, toDegrees,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f);rotate.setDuration(durationMillis);rotate.setFillAfter(true);return rotate;}} 主Activity:TestActivity
package com.example.button; import android.view.View; import android.view.View.OnClickListener; import android.widget.RelativeLayout; import android.widget.Toast; public class TestActivity extends BaseActivity { private ComposerLayout clayout; @Override public void setView() { setContentView(R.layout.activity_main); } @Override public void initView() { // 引用控件 clayout = (ComposerLayout) findViewById(R.id.test); clayout.init(new int[] { R.drawable.composer_camera, R.drawable.composer_music, R.drawable.composer_place, R.drawable.composer_sleep, R.drawable.composer_thought, R.drawable.composer_with }, R.drawable.composer_button, R.drawable.composer_icn_plus, ComposerLayout.RIGHTCENTER, 180, 300); } @Override public void setListener() { // 点击事件监听,100+0对应composer_camera,100+1对应composer_music……如此类推你有机个按钮就加几个按钮都行。 OnClickListener clickit = new OnClickListener() { @Override public void onClick(View v) { if (v.getId() == 100 + 0) { Toast.makeText(TestActivity.this, "测试A", 0).show(); } else if (v.getId() == 100 + 1) { Toast.makeText(TestActivity.this, "测试B...", 0).show(); } else if (v.getId() == 100 + 2) { Toast.makeText(TestActivity.this, "测试C...", 0).show(); } else if (v.getId() == 100 + 3) { Toast.makeText(TestActivity.this, "测试D...", 0).show(); } else if (v.getId() == 100 + 4) { Toast.makeText(TestActivity.this, "测试E...", 0).show(); } else if (v.getId() == 100 + 5) { Toast.makeText(TestActivity.this, "测试F..", 0).show(); } } }; clayout.setButtonsOnClickListener(clickit); RelativeLayout rl = (RelativeLayout) findViewById(R.id.rlparent); rl.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Toast.makeText(TestActivity.this, "父控件可以点击的哦!!!", 0).show(); System.out.println("父控件可以点击。"); } }); } }
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/rlparent" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#ABCDEF" > <com.example.button.ComposerLayout android:id="@+id/test" android:layout_width="20dp" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" > </com.example.button.ComposerLayout> </RelativeLayout>
下载Demo