Android实现卫星菜单效果
作者:爱码士_yan 发布时间:2021-12-12 23:44:28
标签:Android,卫星菜单
前言
最近需求中,需要实现 卫星菜单的需求,最终通过自定义View和动画属性来实现,具体功能如下:
1.自定义View
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.RotateAnimation;
import android.view.animation.TranslateAnimation;
import com.xinrui.headsettest.R;
/**
* 卫星菜单
*/
public class SatelliteView extends ViewGroup {
private View mBtnView;
private MenuStatus mBStatus = MenuStatus.STATUS_CLOSE;
private onSubItemClickListener onListener;
public enum MenuStatus {
STATUS_OPEN, STATUS_CLOSE
}
//子菜单点击接口
public interface onSubItemClickListener {
void onItemClick(View view, int position);
}
public void setOnSubItemClickListener(onSubItemClickListener mListener) {
this.onListener = mListener;
}
public SatelliteView(Context context) {
super(context);
// this(context, null);
}
public SatelliteView(Context context, AttributeSet attrs) {
super(context, attrs);
// this(context, attrs, 0);
}
public SatelliteView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
for (int i = 0; i < count; i++) {
measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
//添加布局,就是所要显示的控件View
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
//主菜单按钮
onMainButton();
//子菜单按钮
onSubItemButton();
}
}
//获取主菜单按钮
private void onMainButton() {
mBtnView = getChildAt(0);
mBtnView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//主菜单动画旋转动画
Animation rotateAnim = AnimationUtils.loadAnimation(getContext(), R.anim.satellite_anim);
mBtnView.startAnimation(rotateAnim);
//子菜单动画
subItemAnim();
}
});
int l, t, r = 0, b = 0;
int mWidth = mBtnView.getMeasuredWidth();
int mHeight = mBtnView.getMeasuredHeight();
l = getMeasuredWidth() - mWidth;
t = getMeasuredHeight() - mHeight;
mBtnView.layout(l, t, getMeasuredWidth(), getMeasuredHeight());
}
//获取子菜单按钮
private void onSubItemButton() {
int count = getChildCount();
for (int i = 0; i < count - 1; i++) {
View childView = getChildAt(i + 1);
//开始时不呈现子菜单
childView.setVisibility(View.GONE);
int radius = 350;
int cl, ct, cr, cb;
cr = (int) (radius * Math.sin(Math.PI / 2 / (count - 2) * i));
cb = (int) (radius * Math.cos(Math.PI / 2 / (count - 2) * i));
int cWidth = childView.getMeasuredWidth();
int cHeight = childView.getMeasuredHeight();
cl = getMeasuredWidth() - cWidth - cr;
ct = getMeasuredHeight() - cHeight - cb;
//layout(l,t,r,b);前两参数决定位置,后两参数决定大小
//参数(1,t)为View控件的左上角坐标
// (r-l,b-t)为View控件大小,r-l为控件宽度,b-t为控件高度
childView.layout(cl, ct, getMeasuredWidth() - cr, getMeasuredHeight() - cb);
}
}
//子菜单散开回笼动画
public void subItemAnim() {
int count = getChildCount();
for (int i = 0; i < count - 1; i++) {
final View childView = getChildAt(i + 1);
//点击主菜单后,子菜单就立刻呈现,否则后面的动画无法完成
childView.setVisibility(VISIBLE);
int radius = 350;
int l, t, r, d;
r = (int) (radius * Math.sin(Math.PI / 2 / (count - 2) * i));
d = (int) (radius * Math.cos(Math.PI / 2 / (count - 2) * i));
// int cWidth = cView.getMeasuredWidth();
// int cHeight = cView.getMeasuredHeight();
//
// l = getMeasuredWidth() - cWidth - r;
// t = getMeasuredHeight() - cHeight - d;
AnimationSet mAnimationSet = new AnimationSet(true);
Animation mTranAnimation = null;
if (mBStatus == MenuStatus.STATUS_CLOSE) {
//散开动画
mTranAnimation = new TranslateAnimation(r, 0, d, 0);
childView.setClickable(true);
childView.setFocusable(true);
} else {
//回笼动画
mTranAnimation = new TranslateAnimation(0, r, 0, d);
childView.setClickable(false);
childView.setFocusable(false);
}
mTranAnimation.setDuration(300);
// tranAnim.setFillAfter(true); //让最后一帧的动画不消失
mTranAnimation.setStartOffset(100 * i / count);
mTranAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (mBStatus == MenuStatus.STATUS_CLOSE) {
childView.setVisibility(GONE);
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
Animation rotateAnim = new RotateAnimation(
0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnim.setDuration(300);
// rotateAnim.setFillAfter(false);
mAnimationSet.addAnimation(rotateAnim);
mAnimationSet.addAnimation(mTranAnimation);
childView.startAnimation(mAnimationSet);
//散开后子菜单的点击监听事件
final int pos = i + 1;
childView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (onListener != null) {
onListener.onItemClick(childView, pos);
}
//散开后点击子菜单动画
subItemClickAnim(pos - 1);
changStatus();
}
});
}
changStatus();
}
//监听子菜单状态改变
private void changStatus() {
mBStatus = (mBStatus == MenuStatus.STATUS_CLOSE ? MenuStatus.STATUS_OPEN : MenuStatus.STATUS_CLOSE);
}
//散开后点击子菜单动画
private void subItemClickAnim(int pos) {
int count = getChildCount();
for (int i = 0;i<count-1;i++) {
View mChildView = getChildAt(i+1);
if(i == pos) {
//变大,变透明
mChildView.startAnimation(toBig());
}
else {
//变小,变透明
mChildView.startAnimation(toSmall());
}
mChildView.setClickable(false);
mChildView.setFocusable(false);
}
}
//变大,变透明
private Animation toBig(){
Animation big = AnimationUtils.loadAnimation(getContext(), R.anim.bigalpha);
return big;
}
//变小,变透明
private Animation toSmall(){
Animation small = AnimationUtils.loadAnimation(getContext(),R.anim.smallalpha);
return small;
}
//给ListView调用
public boolean isOpen() {
return mBStatus == MenuStatus.STATUS_OPEN;
}
}
2.SatelliteActivity
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import com.xinrui.headsettest.arc.SatelliteView;
import java.util.ArrayList;
import java.util.List;
public class SatelliteActivity extends Activity {
private SatelliteView mSatelliteView;
private ListView mListView;
private List<String> mData;
private ArrayAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.satellite_layout);
mSatelliteView = (SatelliteView) findViewById(R.id.view_arc);
mSatelliteView.setOnSubItemClickListener(new SatelliteView.onSubItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(SatelliteActivity.this, "position" + position, Toast.LENGTH_SHORT).show();
}
});
initListView();
}
private void initListView() {
mListView = (ListView) findViewById(R.id.listview);
mData = new ArrayList<String>();
for (int i = 'A'; i <= 'z'; i++) {
mData.add((char) i + "");
}
mAdapter = new ArrayAdapter<String>(
SatelliteActivity.this, android.R.layout.simple_list_item_1, mData);
mListView.setAdapter(mAdapter);
mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (mSatelliteView.isOpen()) {
mSatelliteView.subItemAnim();
}
}
});
}
}
3.satellite_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.xinrui.headsettest.arc.SatelliteView
android:id="@+id/view_arc"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/menu" />
</RelativeLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/camera" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/chat" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/contacts" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/music" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/moon" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/location" />
</com.xinrui.headsettest.arc.SatelliteView>
</RelativeLayout>
4.anim动画 在res 新建anim文件夹
satellite_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:duration="300"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"/>
</set>
bigalpha.xml
<!--android:fillAfter="true"得加,取动画结束后的最后一帧-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<alpha
android:duration="200"
android:fromAlpha="1"
android:toAlpha="0"/>
<scale
android:duration="200"
android:fromXScale="1"
android:fromYScale="1"
android:toXScale="3"
android:toYScale="3"
android:pivotX="50%"
android:pivotY="50%" />
</set>
smallalpha.xml
<!--android:fillAfter="true"得加,取动画结束后的最后一帧-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<alpha
android:duration="200"
android:fromAlpha="1"
android:toAlpha="0"/>
<scale
android:duration="200"
android:fromXScale="1"
android:fromYScale="1"
android:toXScale="0"
android:toYScale="0"
android:pivotX="50%"
android:pivotY="50%" />
</set>
来源:https://blog.csdn.net/baidu_41666295/article/details/106909156
0
投稿
猜你喜欢
- 项目演示演示中只用一个用户登录,只是为了测试功能,实际使用中是根据数据库表内数据来决定的。1 创建工程完成配置1 ieda新建maven项目
- 过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来
- 目录一、集合框架的概述二、集合框架(Java集合可分为Collection 和 Map 两种体系)三、Collection接口中的方法的使用
- 在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理
- 前言植物大战僵尸的数据文件是存储在本地的dat文件当中,修改在本地的dat文件就可以修改到游戏中的数据。之前使用二进制编码工具Hex Edi
- 前言在服务器上,当我们启动了tomcat,就可以以http://ip地址:8080/文件路径/文件名的方式,进行访问到我们服务器上处于tom
- 目录实现方法问题在出问题的设备上,使用简单的Show()、Active()方法激活窗口是不行的,只会在任务栏闪烁图标,使用如下方法可以激活实
- 当遇到以下场景:其他人写的单元测试影响统计结果一些需要调用外部接口的测试暂不运行需要在非本机环境上运行一些不回滚的单元测试则有必要选择以下方
- 一、什么是委托呢?听着名字挺抽象,确实不好理解。面试官最喜欢考察这个,而且更喜欢问:“委托和事件有何异同?”。如果对一些知识点没有想明白,那
- 简介API Gateway,时系统的唯一对外的入口,介于客户端和服务端之间的中间层,处理非业务功能,提供路由请求,鉴权,监控,缓存,限流等功
- AnimationListener听名字就知道是对Animation设置 * ,说简单点就是在Animation动画效果开始执行前,执行完毕
- 在开始之前,我先卖个关子提一个问题:假设我们有一个Movie类,这个类有三个成员变量分别是starred(是否收藏), title(电影名称
- 本文实例讲述了Android滑动按钮事件。分享给大家供大家参考,具体如下:今天纪录一下滑动按钮功能。。首先效果图:然后是分别建立三个文件,第
- 前言最近在使用Spring框架时遇到了一些问题,主要是Spring的事务传播问题,一个不带事务的方法调用带事务的方法,有时候会出现不回滚的情
- 本文实例讲述了C#中DataGridView常用操作。分享给大家供大家参考。具体如下:public void Binder1(){ Data
- 比如有海量的文本文件,如订单,页面点击事件的记录,量特别大,很难搞定。那么我们该怎样解决海量数据的计算?1、获取总行数2、计算每个文件中存多
- 本章节更加具体化的学习编译器还有哪些可以优化的方便,让你的应用展现出更好的性能。JIT编译器版本JIT编译器有不同的版本,而最终你使用哪种,
- 这篇文章主要介绍了如何使用java修改文件所有者及其权限,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- 1.引入依赖,版本3.0.0只引入一个即可<dependency> &n
- 写在前面本文讲解的是 SpringBoot 引入容器化技术 Docker 实现一次构建到处运行,包括镜像构建、Docker仓库搭建使用、Do