700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Android项目开发实战—自定义左右菜单

Android项目开发实战—自定义左右菜单

时间:2023-08-07 00:30:07

相关推荐

Android项目开发实战—自定义左右菜单

Android实现自定义左右菜单

功能描述:

在左中右三个区域分别承载三个不同的view,把它全部添加进来,而我们实现左右菜单,就是来控制当前显示的是哪一部分;如果显示中间菜单,就把中间菜单呈现在用户面前;如果显示左菜单,就把左菜单和一部分的中间菜单呈现在用户面前;如果显示右菜单,就把右菜单和一部分的中间菜单呈现在用户面前。即整张图的左中右不断移动。

功能实现(step by step):

1、菜单布局(通过扩展,完成基本布局。包含左右菜单布局和中间内容区域,并设置颜色用于区分)2、菜单左右滑动(使用逻辑,找出滑动中间点,并对事件作处理,主要针对滑动事件)3、加入左右滑动动画(使用Scroll进行滑动事件处理,主要是自动滑动,增加用户体验)4、处理点击事件(通过对左右事件的处理,会阻止点击事件的处理,这里需要调用系统,返还点击事件)5、添加蒙板效果(通过增加view,对view的透明度进行处理,从而实现蒙版效果)

核心内容:

1.布局的添加

2.事件分发机制

3.滚动添加

4.蒙版添加

构想图:

开发过程中遇到的错误:

Caused by:java.lang.IllegalStateException:The specified child already has a parent.You must call removeView() on the child’s parent first.

造成这个原因,是组件在父类中重复加载了相同的组件

如:

addView(leftMenu, mLayout); // 第一次添加

addView((leftMenu, , mLayout); // 第二次添加

源代码:

activity_main.xml:

<RelativeLayout xmlns:android="/apk/res/android"xmlns:tools= "/tools"android:layout_width= "match_parent"android:layout_height= "match_parent"tools:context= ".MainActivity" ></RelativeLayout>

left.xml:

<?xml version= "1.0" encoding ="utf-8"?><LinearLayout xmlns:android="/apk/res/android"android:layout_width= "match_parent"android:layout_height= "match_parent"android:orientation= "vertical" ><Button android:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Button" /></LinearLayout>

MainActivity.java

package com.example.mymenu;import android.os.Bundle;import android.app.Activity;import android.support.v4.app.FragmentActivity;import android.view.Menu;public class MainActivity extends FragmentActivity {private MainUI mainUI ;private LeftMenu leftMenu ;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//实例化MainUImainUI= new MainUI(this );setContentView( mainUI);//实例化LeftMenuleftMenu= new LeftMenu();getSupportFragmentManager().beginTransaction().add(MainUI. LEFT_ID,leftMenu ).commit();}}

MainUI.java

package com.example.mymenu;

import android.annotation.SuppressLint;

import android.content.Context;

import android.graphics.Color;

import android.graphics.Point;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.animation.DecelerateInterpolator;

import android.widget.FrameLayout;

import android.widget.RelativeLayout;

import android.widget.Scroller;

@SuppressLint(“NewApi” )

public class MainUI extends RelativeLayout{

private Context context ;private FrameLayout leftMenu ;private FrameLayout middleMenu ;private FrameLayout rightMenu ;//设置蒙版private FrameLayout middleMask ;private Scroller mScroller ;//定义左中右菜单的IDpublic static final int LEFT_ID=0xaabbcc;public static final int MIDDLE_ID=0xaaccbb;public static final int RIGHT_ID=0xccbbaa;//继承自RelativeLayout,并实现两个构造方法public MainUI(Context context) {super(context);initView(context);}public MainUI(Context context, AttributeSet attrs) {super(context, attrs);initView(context);}public void initView(Context context){this.context =context;mScroller=new Scroller(context, new DecelerateInterpolator()); //渲染器//实例化三个区域leftMenu= new FrameLayout(context);middleMenu=new FrameLayout(context);rightMenu=new FrameLayout(context);middleMask=new FrameLayout(context);//分别为三个区域添加不同的颜色leftMenu.setBackgroundColor(Color. RED);middleMenu.setBackgroundColor(Color.GREEN);rightMenu.setBackgroundColor(Color.RED);middleMask.setBackgroundColor(0x88000000);//蒙版的初始颜色为浅灰色//为自定义的左中右菜单添加IDleftMenu.setId( LEFT_ID);middleMenu.setId(MIDDLE_ID );rightMenu.setId(RIGHT_ID ); //把三个区域全部填充到一个view中,实际上这个view就是我们承载三个区域的最外层的RelativeLayout,也是当前的主文件addView( leftMenu);addView( middleMenu);addView( rightMenu);addView( middleMask);middleMask.setAlpha(0);//设置蒙版的科技度(完全可见),只有在滑动的时候才是不可见的}public float onMiddleMask(){System. out.println("透明度:" +middleMask .getAlpha());return middleMask .getAlpha();}//根据滑动的距离的变化来设置可见度值的变化@Overridepublic void scrollTo(int x, int y) {super.scrollTo(x, y);onMiddleMask();int curX=Math.abs(getScrollX());float scale=curX/(float)leftMenu.getMeasuredWidth(); //计算整个可见宽度middleMask.setAlpha(scale);}//在把三个区域添加到Layout之前,先对它们的宽和高进行测量@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {//widthMeasureSpec,heightMeasureSpec是当前屏幕的宽度和高度super.onMeasure(widthMeasureSpec, heightMeasureSpec);//中间菜单的宽和高即为当前屏幕的宽和高middleMenu.measure(widthMeasureSpec, heightMeasureSpec);//获取蒙版的宽和高middleMask.measure(widthMeasureSpec, heightMeasureSpec);//得到当前屏幕的真实宽度int realWidth=MeasureSpec.getSize(widthMeasureSpec);//计算所需要的宽度int tempWidthMeasure=MeasureSpec.makeMeasureSpec(( int)(realWidth*0.8f),MeasureSpec.EXACTLY);//为左右菜单设置相应的宽度leftMenu.measure(tempWidthMeasure, heightMeasureSpec);rightMenu.measure(tempWidthMeasure, heightMeasureSpec); }//把三个区域添加到Layout中@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {//五个参数(改变监听,left,top,right,bottom)super.onLayout(changed, l, t, r, b);//设置三个区域在layout中的位置middleMenu.layout(l, t, r, b);middleMask.layout(l, t, r, b);leftMenu.layout(l- leftMenu.getMeasuredWidth(), t, l, b);//(l-leftMenu.getMeasuredWidth(), t, r, b)rightMenu.layout(r,t,r+ rightMenu.getMeasuredWidth(),b); //(l+middleMenu.getMeasuredWidth(), t, l+middleMenu.getMeasuredWidth()+rightMenu.getMeasuredWidth(), b)}private boolean isTestCompete ;private boolean isleftrightEvent ;//标识上下滑动和左右滑动,左右滑动为true,上下滑动为false//事件分发@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {//检测到一个事件,判断是什么事件(上下滑动事件、左右滑动事件、点击事件)if (!isTestCompete ) {//没有初始化,默认为falsegetEventType(ev); //创建一个判断处理事件的方法return true ;}if (isleftrightEvent ) {//左右滑动应该触发的响应switch (ev.getActionMasked()) {case MotionEvent.ACTION_MOVE://你手指滑动的距离即为当前屏幕滑动的距离int curScrollX=getScrollX();//定义屏幕滑动的距离int dis_x=(int )(ev.getX()-point.x);//定义手指滑动的距离int expectX=-dis_x+curScrollX;//根据差值判断是向左滑动还是向右滑动(差值大于20是向右滑动;差值小于20是向左滑动)int finalX=0; //定义屏幕最终的左右滑动距离if (expectX<0) {//向左finalX=Math. max(expectX, -leftMenu.getMeasuredWidth());//最大值} else{ //向右finalX=Math. min(expectX, rightMenu.getMeasuredWidth());//最小值}scrollTo(finalX, 0); //使屏幕移动到最终的位置point. x=( int)ev.getX();break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:curScrollX=getScrollX();if (Math.abs(curScrollX)> leftMenu.getMeasuredWidth() >> 1) {//当屏幕滑动的距离大于左右菜单的一半时,自动跳到相应的菜单if (curScrollX<0) {mScroller.startScroll(curScrollX,0,- leftMenu.getMeasuredWidth()-curScrollX, 0,200); //起始X,起始Y,终止X,终止Y} else {mScroller.startScroll(curScrollX,0,leftMenu.getMeasuredWidth()-curScrollX, 0,200);}} else {//返回原点mScroller.startScroll(curScrollX,0,-curScrollX, 0,200);}invalidate(); //调用view的重绘方法进行刷新isleftrightEvent=false ;isTestCompete=false ; break;}} else{//对上下滑动和点击触发的响应switch (ev.getActionMasked()) {case MotionEvent.ACTION_UP:isleftrightEvent=false ;isTestCompete=false ;break;default: break;}}return super .dispatchTouchEvent(ev);}//重写回调方法,使左右菜单进行滑动@Overridepublic void computeScroll() {puteScroll();if (mScroller .computeScrollOffset()) {return;}int tempX=mScroller .getCurrX();scrollTo(tempX, 0);}private Point point =new Point(); //获取当前屏幕的点,通过点来计算滑动的距离,根据滑动的距离来判断相应的事件是滑动还是点击private static final int TEST_DIS=20; //如果移动距离大于20就定义为滑动//判断处理事件private void getEventType(MotionEvent ev) {switch (ev.getActionMasked()) {case MotionEvent.ACTION_DOWN:point. x=( int) ev.getX();//floatpoint. y=( int) ev.getY();super.dispatchTouchEvent(ev);break;case MotionEvent.ACTION_MOVE:int dX= Math.abs(( int)ev.getX()-point .x );//获取水平方向上移动距离的绝对值int dY=Math.abs(( int)ev.getY()-point .y );//获取垂直方向上移动距离的绝对值if (dX>=TEST_DIS && dX>dY) {//左右滑动isleftrightEvent=true ;isTestCompete=true ; //允许进入接下来的返出测试阶段//获取当前点的 xy坐标point. x=( int) ev.getX();//floatpoint. y=( int) ev.getY();} else if (dY>=TEST_DIS && dY>dX) { //上下滑动isleftrightEvent=false ;isTestCompete=true ;//允许进入接下来的返出测试阶段point. x=( int) ev.getX();//floatpoint. y=( int) ev.getY();}break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL://触摸到屏幕的边缘//对点击事件进行处理(返还给系统处理)super.dispatchTouchEvent(ev);isleftrightEvent=false ;isTestCompete=false ;break;}}

}

LeftMeau.java:

package com.example.mymenu;import android.os.Bundle;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;public class LeftMenu extends Fragment{@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View v=inflater.inflate(R.layout. left, container,false);//引入left.xml布局文件//为button按钮添加监听事件v.findViewById(R.id. button1).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {System. out.println("Hello LMB!!" ); }});return v;}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。