1.自定义布局继承RelativeLayout:
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 myAnimations 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; } 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())*2); } } 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]; 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); 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); 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 myAnimations(rl1, pCode, radius); rlButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (areButtonsShowing) { myani.startAnimationsOut(duretime); cross.startAnimation(myAnimations.getRotateAnimation(-270, 0, duretime)); } else { myani.startAnimationsIn(duretime); cross.startAnimation(myAnimations.getRotateAnimation(0, -270, duretime)); } areButtonsShowing = !areButtonsShowing; } }); cross.startAnimation(myAnimations.getRotateAnimation(0, 360, 200)); this.addView(rl1); this.addView(rlButton); hasInit = true; } public void collapse() { myani.startAnimationsOut(duretime); cross.startAnimation(myAnimations.getRotateAnimation(-270, 0, duretime)); areButtonsShowing = false; } public void expand() { myani.startAnimationsIn(duretime); cross.startAnimation(myAnimations.getRotateAnimation(0, -270, duretime)); areButtonsShowing = true; } public boolean isInit() { return hasInit; } public boolean isShow() { return areButtonsShowing; } 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); } }); } } } }
2.定义动画类:
public class myAnimations { 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; private final int amount; private double fullangle = 180.0; private byte xOri = 1, yOri = 1; private boolean isOpen = false; private List<ViewPropertyAnimator> viewAnimators = new ArrayList<ViewPropertyAnimator>(); public myAnimations(ViewGroup comlayout, int poscode, int radius) { this.pc = poscode; this.clayout = comlayout; this.amount = clayout.getChildCount(); this.R = radius; 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 } } 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; } 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; } }
自定义动画需要用到nineoldandroids类。
3.布局文件:
<LinearLayout 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" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:text="@string/hello_world" android:textColor="#000000" tools:context=".MainActivity" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/hello_world" android:textColor="#000000" tools:context=".MainActivity" /> <geniuz.myPathbutton.composerLayout android:id="@+id/test" android:layout_width="150dp" android:layout_height="wrap_content" android:layout_alignParentBottom="true" > </geniuz.myPathbutton.composerLayout> </RelativeLayout> </LinearLayout> </LinearLayout>
4。用法:
composerLayout 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.CENTERBOTTOM, 180, 300); OnClickListener clickit = new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if (v.getId() == 100 + 0) { System.out.println("composer_camera"); } else if (v.getId() == 100 + 1) { System.out.println("composer_music"); } else if (v.getId() == 100 + 2) { System.out.println("composer_place"); } else if (v.getId() == 100 + 3) { System.out.println("composer_sleep"); } else if (v.getId() == 100 + 4) { System.out.println("composer_thought"); } else if (v.getId() == 100 + 5) { System.out.println("composer_with"); } } }; clayout.setButtonsOnClickListener(clickit);
相关推荐
"android仿path半圆形菜单"就是一个很好的示例,它旨在实现与Path应用类似的半圆形菜单效果,为用户提供新颖的操作体验。Path是一款社交网络应用,其设计风格一直受到开发者们的青睐。下面,我们将深入探讨如何在...
对于“半圆形”和“圆形”的中间布局,开发者需要考虑如何在保持菜单项均匀分布的同时,使它们沿圆形轨迹排列。这需要对圆周率π有深入的理解,并且要正确处理角度的增量。半圆形布局则意味着只有一半的圆周被利用,...
在Android开发中,创建独特和吸引用户的界面是至关重要的,Path菜单就是这样一种创新的设计元素。本文将深入探讨如何利用三角函数来实现一个仿照Path应用的菜单,支持半圆、圆形以及1/4圆的布局,同时提供左上、右上...
本源码主要演示使用Android的TranslateAnimation方法实现点击展开的半圆形PathMenu菜单,原来PATH的菜单效果如此简单。布局 TranslateAnimation就可以搞定了。如视图所示的运行效果,单击在右下角的“ ”图标,会...
本教程将详细解析如何在Android平台上实现一个从底部滑出的半圆形菜单。这个菜单不仅能够提供一种新颖的用户体验,还可以帮助优化屏幕空间利用,使应用更具现代感。 首先,我们需要了解Android布局系统。在Android...
"android 仿 path 苹果 iphone"这个项目旨在帮助Android开发者实现Path应用中独特的半圆形弹出动画菜单,它位于屏幕的左下角,点击后能够以半圆形的方式展开,为用户带来流畅的交互体验。 首先,我们需要理解Path...
"仿Android建行客户端中可滑动半圆形按钮"这一技术实现,主要是为了创建一个类似中国建设银行移动应用中的交互元素,它是一个可滑动的半圆形菜单,用户可以通过滑动来选择不同的功能或者操作。这种设计既美观又实用...
用户点击或触摸中心点后,菜单项会以某种预定的轨迹,通常是圆形或半圆形,展开或收起。这种设计通常与汉堡菜单(三线菜单)形成对比,提供了一种更加动态的用户体验。 要实现这样的菜单,开发者需要掌握以下几个...
"android圆形旋转菜单,并支持移动换位功能"是一个创新的交互设计,旨在为用户提供有趣且直观的操作方式。这种菜单通常用于显示多个选项,用户可以通过手势或点击来旋转菜单,选择不同的功能。接下来,我们将深入...
在Android中,可以使用`Canvas`和`Paint`对象进行绘制,配合`Path`来描绘复杂的图形路径,实现圆形的形状。 在实际开发过程中,开发者可能需要用到`onDraw()`方法来绘制菜单的背景和菜单项。为了实现旋转效果,通常...
ArcMenu 是一个在 Android 开发中常见的可自定义动画效果的菜单库,它受到了著名社交应用 Path 的启发,提供了类似半圆形展开的菜单效果。这个压缩包包含了实现 ArcMenu 功能的源代码,通过分析这些代码,我们可以...
这通常需要用到编程语言中的图形库,如JavaScript中的Canvas API或者Android中的Path和Paint类。在图形绘制时,需要精确计算每个菜单项的位置,使其均匀分布在圆周上。 2. **动画效果**:为了让菜单具有转动的效果...
在这个方法中,使用Canvas对象绘制半圆形的菜单背景以及各个菜单项。 2. **Path和Paint对象**:Path对象用于定义菜单项的路径,Paint对象则用于设置颜色、描边等图形属性。开发者需要计算每个菜单项相对于圆心的...
这种菜单以其独特的半圆形展示方式,为用户提供了新颖的操作体验。在Android平台上,开发者可以利用各种库和自定义视图来实现这种效果。下面我们将深入探讨半圆动画菜单的实现原理、相关技术以及如何在自己的项目中...
描述中的“水平方向伸缩的path按钮菜单非弧形.rar”再次强调了这个资源的特点,即菜单项沿着水平轴扩展或收缩,而且不是传统的圆形或半圆形布局。这可能涉及到Android的自定义视图和动画处理。 标签“android”表示...
这个`ArcMenu`仿Path按钮的源码分析将帮助我们深入理解如何在Android平台上实现这种动态弧形展开的菜单。 首先,`ArcMenu`的核心在于它的动画效果。当用户点击按钮时,菜单项会沿着一个半圆形轨迹滑出,形成一种...
"以圆心散开的半圆菜单"是一种创新的交互设计,它将菜单项以半圆形排列,且从圆心向外展开,既美观又具有动态效果。这种设计通常用于需要展现多个选项但又希望保持界面简洁的情况,例如设置界面或者导航菜单。 首先...
这种菜单不是通常的圆形或半圆形展开方式,而是采用水平方向的伸缩效果,为用户界面带来了独特的交互体验。Path按钮通常涉及到Android的图形绘制,它可能利用了`Path`类来定义和绘制菜单项的形状和路径,通过动画...
Path类用于构建菜单项的路径,包括半圆形的边框和每个菜单项的位置。 3. **动画框架(Animation Framework)**:为了实现以圆心散开的效果,开发者需要使用Android的动画框架,如ValueAnimator、ObjectAnimator或者...