Android高手进阶篇4-实现侧滑菜单框架,一分钟集成到项目中

先来看下面的这张效果图:

上面这张效果图是百度影音的,现在在Android上很流行,最初是由facebook自己实现的,而后各大应用有跟风之势,那么这种侧滑效果是如何实现的呢?

网上现在这种侧滑菜单的例子很对,也有开源的框架sliderMenu,而且可以定义很多样式,但大部分例子,都只是实现了这种类似效果,没有实现一种可移植的框架,仅仅是单页面效果而已,而且集成起来复杂,鉴于此,我自己实现了一套侧滑菜单的框架:

1、最常用的支持左右策划

2、多个页面切换也好不费力,页面切换的逻辑已经实现好了,集成进来,只需要关注自己项目的业务逻辑

3、支持多个页面集成

4、支持退出业务逻辑

先上我自己实现的效果图:

下面 说一下实现原理:

布局文件采用FrameLayout, 在一个FrameLayout下有二个子布局,一个是菜单,另一个是LeftSliderLayout,而LeftSliderLayout下面可以放二个子布局:第一个是阴影布局(左边阴影),第二个是要拖动的内容。,当向右拖动LeftSliderLayout时,就显示露出菜单布局。而向左拖动LeftSliderLayout时,就覆盖菜单布局。

1.FrameLayout的布局文件local_media_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <include android:id="@+id/main_layout_below" layout="@layout/main_layout_below" />

    <com.zhaoxufeng.leftsliderlayout.lib.LeftSliderLayout
        android:id="@+id/main_slider_layout"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <!-- Shadow Child -->
        <ImageView
                android:layout_width="15px"
                android:layout_height="fill_parent"
                android:contentDescription="@null"
                android:scaleType="fitXY"
                android:src="@drawable/main_side_shadow" />

        <!-- Main Child -->
        <include android:id="@+id/main_slider_main" layout="@layout/local_media" />

    </com.zhaoxufeng.leftsliderlayout.lib.LeftSliderLayout>

</FrameLayout>

上面 xml 中main_layout_below是对应的左边菜单Menu布局文件(这个布局文件是固定的),local_media是你要的拖动布局

2、LeftSliderLayout.java代码

package com.zhaoxufeng.leftsliderlayout.lib;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;

public class LeftSliderLayout extends ViewGroup {

    private static final String TAG = "LeftSliderLayout"  ;

    private Scroller mScroller;
    private VelocityTracker mVelocityTracker;

    /**
     * Constant value for touch state
     * TOUCH_STATE_REST : no touch
     * TOUCH_STATE_SCROLLING : scrolling
     */
    private static final int TOUCH_STATE_REST = 0;
    private static final int TOUCH_STATE_SCROLLING = 1;
    private int mTouchState = TOUCH_STATE_REST;

    /**
     * Distance in pixels a touch can wander before we think the user is scrolling
     */
    private int mTouchSlop;

    /**
     * Values for saving axis of the last touch event.
     */
    private float mLastMotionX;
    private float mLastMotionY;

    /**
     * Values for VelocityTracker to compute current velocity.
     * VELOCITY_UNITS in dp
     * mVelocityUnits in px
     */
    private static final int VELOCITY_UNITS = 1000;
    private int mVelocityUnits;    

    /**
     * The minimum velocity for determining the direction.
     * MINOR_VELOCITY in dp
     * mMinorVelocity in px
     */
    private static final float MINOR_VELOCITY = 150.0f;
    private int mMinorVelocity;                                

    /**
     * The width of Sliding distance from left.
     * And it should be the same with the width of the View below SliderLayout in a FrameLayout.
     * DOCK_WIDTH in dp
     * mDockWidth in px
     */
    private static final float SLIDING_WIDTH = 270.0f;
    private int mSlidingWidth;                                    

    /**
     * The default values of shadow.
     * VELOCITY_UNITS in dp
     * mVelocityUnits in px
     */
    private static final float DEF_SHADOW_WIDTH = 10.0f;
    private int mDefShadowWidth;                                

    /**
     * Value for checking a touch event is completed.
     */
    private boolean mIsTouchEventDone = false;                

    /**
     * Value for checking slider is open.
     */
    private boolean mIsOpen = false;                        

    /**
     * Value for saving the last offset of scroller ’ x-axis.
     */
    private int mSaveScrollX = 0;                            

    /**
     * Value for checking slider is allowed to slide.
     */
    private boolean mEnableSlide = true;                    

    private View mMainChild = null;
    private OnLeftSliderLayoutStateListener mListener = null;

    /**
     * Instantiates a new LeftSliderLayout.
     *
     * @param context the associated Context
     * @param attrs AttributeSet
     */
    public LeftSliderLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * Instantiates a new LeftSliderLayout.
     *
     * @param context the associated Context
     * @param attrs AttributeSet
     * @param defStyle Style
     */
    public LeftSliderLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mScroller = new Scroller(context);
        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

        /**
         * Convert values in dp to values in px;
         */
        final float fDensity = getResources().getDisplayMetrics().density;
        mVelocityUnits = (int) (VELOCITY_UNITS * fDensity + 0.5f);
        mMinorVelocity = (int) (MINOR_VELOCITY * fDensity + 0.5f);
        mSlidingWidth = (int) (SLIDING_WIDTH * fDensity + 0.5f);
        mDefShadowWidth = (int) (DEF_SHADOW_WIDTH * fDensity + 0.5f);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // check Measure Mode is Exactly.
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        if (widthMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("LeftSliderLayout only canmCurScreen run at EXACTLY mode!");
        }
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("LeftSliderLayout only can run at EXACTLY mode!");
        }

        // measure child views
        int nCount = getChildCount();
        for (int i = 2; i < nCount; i++) {
            removeViewAt(i);
        }
        nCount = getChildCount();
        if (nCount > 0) {
            if (nCount > 1) {
                mMainChild = getChildAt(1);
                getChildAt(0).measure(widthMeasureSpec, heightMeasureSpec);
            } else {
                mMainChild = getChildAt(0);
            }
            mMainChild.measure(widthMeasureSpec, heightMeasureSpec);
        }

        // Set the scrolled position
        scrollTo(mSaveScrollX, 0);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int nCount = getChildCount();
        if (nCount <= 0) {
            return;
        }

        // Set the size and position of Main Child
        if (mMainChild != null) {
            mMainChild.layout(
                l,
                t,
                l + mMainChild.getMeasuredWidth(),
                t + mMainChild.getMeasuredHeight());
        }

        // Set the size and position of Shadow Child
        if (nCount > 1) {
            int nLeftChildWidth = 0;
            View leftChild = getChildAt(0);
            ViewGroup.LayoutParams layoutParams = leftChild.getLayoutParams();
            if (layoutParams.width == ViewGroup.LayoutParams.FILL_PARENT
                    || layoutParams.width == ViewGroup.LayoutParams.MATCH_PARENT) {
                nLeftChildWidth = mDefShadowWidth;
            } else {
                nLeftChildWidth = layoutParams.width;
            }
            leftChild.layout(
                    l - nLeftChildWidth,
                    t,
                    l,
                    t + leftChild.getMeasuredHeight());
        }
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            Log.d(TAG,"computeScroll exeuted:" + "x:" + mScroller.getCurrX() + "Y:" + mScroller.getCurrY())  ;
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) { 

        int nCurScrollX = getScrollX();

        // check touch point is in the rectangle of Main Child
        if (mMainChild != null
                && mTouchState != TOUCH_STATE_SCROLLING
                && mIsTouchEventDone) {
            Rect rect = new Rect();
            mMainChild.getHitRect(rect);
            if (!rect.contains((int)event.getX() + nCurScrollX, (int)event.getY())) {
                return false;
            }
        }

        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }

        mVelocityTracker.addMovement(event);

        final int action = event.getAction();
        final float x = event.getX();

        switch (action) {
        case MotionEvent.ACTION_DOWN: {
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }

            mIsTouchEventDone = false;
            mLastMotionX = x;
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            // check slider is allowed to slide.
            if (!mEnableSlide) {
                break;
            }

            // compute the x-axis offset from last point to current point
            int deltaX = (int) (mLastMotionX - x);
            if (nCurScrollX + deltaX < getMinScrollX()) {
                deltaX = getMinScrollX() - nCurScrollX;
                mLastMotionX = mLastMotionX - deltaX;
            } else if (nCurScrollX + deltaX > getMaxScrollX()) {
                deltaX = getMaxScrollX() - nCurScrollX;
                mLastMotionX = mLastMotionX - deltaX;
            } else {
                mLastMotionX = x;
            }

            // Move view to the current point
            if (deltaX != 0) {
                scrollBy(deltaX, 0);
            }

            // Save the scrolled position
            mSaveScrollX = getScrollX();
            break;
        }

        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP: {

            // check slider is allowed to slide.
            if (!mEnableSlide) {
                break;
            }

            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(mVelocityUnits);

            // Set open or close state, when get ACTION_UP or ACTION_CANCEL event.
            if (nCurScrollX < 0) {
                int velocityX = (int) velocityTracker.getXVelocity();
                if (velocityX > mMinorVelocity) {
                    scrollByWithAnim(getMinScrollX() - nCurScrollX);
                    setState(true);
                }
                else if (velocityX < -mMinorVelocity) {
                    scrollByWithAnim(-nCurScrollX);
                    setState(false);
                } else {
                    if (nCurScrollX >= getMinScrollX() / 2) {
                        scrollByWithAnim(- nCurScrollX);
                        setState(false);
                    } else {
                        scrollByWithAnim(getMinScrollX() - nCurScrollX);
                        setState(true);
                    }
                }
            } else {
                if (nCurScrollX > 0) {
                    scrollByWithAnim(-nCurScrollX);
                }
                setState(false);
            }

            if (mVelocityTracker != null) {
                mVelocityTracker.recycle();
                mVelocityTracker = null;
            }

            mTouchState = TOUCH_STATE_REST;
            mIsTouchEventDone = true;
            break;
        }

        }
        return true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        final int action = ev.getAction();

        if (mListener != null && !mListener.OnLeftSliderLayoutInterceptTouch(ev)) {
            return false;
        }

        if ((action == MotionEvent.ACTION_MOVE)
                && (mTouchState != TOUCH_STATE_REST)) {
                 return true;
        }

        final float x = ev.getX();
        final float y = ev.getY();
        switch (action) {
        case MotionEvent.ACTION_DOWN:
                 mLastMotionX = x;
                 mLastMotionY = y;
                 mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
                 break;

        case MotionEvent.ACTION_MOVE:
                 final int xDiff = (int) Math.abs(mLastMotionX - x);
                 if (xDiff > mTouchSlop) {
                          if (Math.abs(mLastMotionY - y) / Math.abs(mLastMotionX - x) < 1)
                                   mTouchState = TOUCH_STATE_SCROLLING;
                }
                break;

        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
                 mTouchState = TOUCH_STATE_REST;
                 break;
        }
        return mTouchState != TOUCH_STATE_REST;
    }

    /**
     * With the horizontal scroll of the animation
     *
     * @param nDx x-axis offset
     */
    void scrollByWithAnim(int nDx) {
        if (nDx == 0) {
            return;
        }

        Log.d(TAG,"scrollByWithAnim:" + "x:" + (getScrollX() + "Y:" + Math.abs(nDx)))  ;
        mScroller.startScroll(getScrollX(), 0, nDx, 0,
                Math.abs(nDx));

        invalidate();
    }

    /**
     * Get distance of the maximum horizontal scroll
     *
     * @return distance in px
     */
    private int getMaxScrollX() {
        return 0;
    }

    /**
     * Get distance of the minimum horizontal scroll
     * @return distance in px
     */
    private int getMinScrollX() {
        return -mSlidingWidth;
    }

    /**
     * Open LeftSlideLayout
     */
    public void open() {
        Log.d(TAG,"scroll by width:" + (getMinScrollX() - getScrollX()))  ;
        if (mEnableSlide) {
            Log.d(TAG,"scroll by width:" + (getMinScrollX() - getScrollX()))  ;
            scrollByWithAnim(getMinScrollX() - getScrollX());
            setState(true);
        }
    }

    /**
     * Close LeftSlideLayout
     */
    public void close() {
        if (mEnableSlide) {
            scrollByWithAnim((-1) * getScrollX());
            setState(false);
        }
    }

    /**
     * Determine whether LeftSlideLayout is open
     *
     * @return true-open,false-close
     */
    public boolean isOpen() {
        return mIsOpen;
    }

    /**
     * Set state of LeftSliderLayout
     *
     * @param bIsOpen the new state
     */
    private void setState(boolean bIsOpen) {
        boolean bStateChanged = false;
        if (mIsOpen && !bIsOpen) {
            bStateChanged = true;
        } else if (!mIsOpen && bIsOpen) {
            bStateChanged = true;
        }

        mIsOpen = bIsOpen;

        if (bIsOpen) {
            mSaveScrollX = getMaxScrollX();
        } else {
            mSaveScrollX = 0;
        }

        if (bStateChanged && mListener != null) {
            mListener.OnLeftSliderLayoutStateChanged(bIsOpen);
        }
    }

    /**
     * enable slide action of LeftSliderLayout
     *
     * @param bEnable
     */
    public void enableSlide(boolean bEnable) {
        mEnableSlide = bEnable;
    }

    /**
     * Set listener to LeftSliderLayout
     */
    public void setOnLeftSliderLayoutListener(OnLeftSliderLayoutStateListener listener) {
        mListener = listener;
    }

    /**
     * LeftSliderLayout Listener
     *
     */
    public interface OnLeftSliderLayoutStateListener { 

        /**
         * Called when LeftSliderLayout’s state has been changed.
         *
         * @param bIsOpen the new state
         */
        public void OnLeftSliderLayoutStateChanged(boolean bIsOpen);

        /**
         * Called when LeftSliderLayout has got onInterceptTouchEvent.
         *
         * @param ev Touch Event
         * @return true - LeftSliderLayout need to manage the InterceptTouchEvent.
         *         false - LeftSliderLayout don‘t need to manage the InterceptTouchEvent.
         */
        public boolean OnLeftSliderLayoutInterceptTouch(MotionEvent ev);
   }
}

LeftSliderLayout有一个Listener。它有二个函数,一个是LeftSliderLayout的打开与关闭的状态改变;另一个是InterceptTouchEvent的回调,主要解决的是在拖动内容中有要处理左右滑动的控件与LeftSliderLayout的左右滑动的事件有冲突,当它返回true时,LeftSliderLayout会处理左右滑动,当它返回false时,就不处理左右滑动的事件。

为了实现侧滑菜单框架,故实现了一个BaseActivity,其他Activity只需要继承这个Activity就行,

3、BaseActivity.java代码

package com.zhaoxufeng.leftsliderlayout.example;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.*;
import com.zhaoxufeng.leftsliderlayout.R;
import com.zhaoxufeng.leftsliderlayout.lib.LeftSliderLayout;

import java.util.ArrayList;
import java.util.List;

/**
 * 基类Activity,SliderMenu的基础统一框架
 * User: zhiwen.nan
 * Date: 13-10-7
 * Time: 下午8:31
 *
 */
public class BaseActivity extends Activity implements LeftSliderLayout.OnLeftSliderLayoutStateListener, View.OnClickListener {

    private  LeftSliderLayout leftSliderLayout;
    private ImageView mOpenButton;
    private TextView mTitleText;
    private ListView mListView;
    private List<ListItem> mDataList;
    private  long waitTime = 2000;
    private  long touchTime = 0;
    private static final  String TAG = "BaseActivity"  ;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void onResume() {
        super.onResume();
        bindView();
        initialDataList();
        ListViewAdapter listViewAdapter = new ListViewAdapter(BaseActivity.this,mDataList) ;
        mListView.setAdapter(listViewAdapter);
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                finish();
                switch (i)  {
                    case 0:
                        mTitleText.setText(getText(R.string.categ_local_video_list));
                        Intent intent = new Intent(BaseActivity.this,LocalMediaActivity.class)  ;
                        startActivity(intent);
                        break;
                    case 1:
                        mTitleText.setText(getText(R.string.cate_leida));
                        Intent radIntent = new Intent(BaseActivity.this,RadoActivity.class)  ;
                        startActivity(radIntent);
                        break;
                    case 2:
                        mTitleText.setText(getText(R.string.hot_viedo));
                        Intent hotIntent = new Intent(BaseActivity.this,HotMediaListActivity.class)  ;
                        startActivity(hotIntent);
                        break;
                    case 3:
                        mTitleText.setText(getText(R.string.cate_favrouite_list));
                        Intent collectIntent = new Intent(BaseActivity.this,CollectListActivity.class)  ;
                        startActivity(collectIntent);
                        break;
                    default:
                        leftSliderLayout.close();
                        break;

                }
            }
        });
    }

    @Override
    public void onClick(View view) {

    }

    @Override
    public void OnLeftSliderLayoutStateChanged(boolean bIsOpen) {

        if (bIsOpen) {
//            Toast.makeText(this, "LeftSliderLayout is open!", Toast.LENGTH_SHORT).show();
            Log.d(TAG," leftsilder is open")  ;
        } else {
           // Toast.makeText(this, "LeftSliderLayout is close!", Toast.LENGTH_SHORT).show();
            Log.d(TAG," leftsilder is close")  ;
        }

    }

    @Override
    public boolean OnLeftSliderLayoutInterceptTouch(MotionEvent ev) {

        return false;
    }

    private  void initialDataList(){
        mDataList = new ArrayList<ListItem>() ;
        for (int i = 0; i<= 3; i ++)       {
            ListItem listItem = new ListItem();
            listItem.setImageType(i);
            mDataList.add(listItem);

        }
    }

    private  void bindView(){
        leftSliderLayout = (LeftSliderLayout) findViewById(R.id.main_slider_layout);
        leftSliderLayout.setOnLeftSliderLayoutListener(this);
        mOpenButton = (ImageView)findViewById(R.id.openButton) ;
        mTitleText = (TextView)findViewById(R.id.titleText) ;
        mListView = (ListView)findViewById(R.id.listTab)  ;

        mOpenButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(leftSliderLayout.isOpen()) {
                    leftSliderLayout.close();
                } else {
                    leftSliderLayout.open();
                }

            }
        });

    }

    public  void openLeftSlider(boolean isToOpen){
        if(isToOpen)    {
            leftSliderLayout.open();
        }else {
            leftSliderLayout.close();
        }

    }

    public  void enableSlider(boolean isEnable)    {
         if(isEnable)  {
              leftSliderLayout.enableSlide(true);
         } else {
             leftSliderLayout.enableSlide(false);
         }
    }

    @Override
    public void onBackPressed() {
        if(!leftSliderLayout.isOpen())   {
            leftSliderLayout.open();
        } else {
            long currentTime = System.currentTimeMillis();
            if((currentTime-touchTime)>=waitTime) {
                Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();
                touchTime = currentTime;
            }else {
                finish();
                //todo
                //退出业务逻辑 ,根据项目需求来写
            }
        }

    }
}

关于左侧菜单的业务逻辑都在BaseActivity里处理,另外返回的逻辑也在里面处理,顶部统一的导航栏打开菜单栏业务逻辑,还有左侧菜单跳转的业务逻辑

4、LocalMediaActivity.java

package com.zhaoxufeng.leftsliderlayout.example;

import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.Contacts;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.*;
import com.zhaoxufeng.leftsliderlayout.R;
import com.zhaoxufeng.leftsliderlayout.lib.LeftSliderLayout;
import com.zhaoxufeng.leftsliderlayout.lib.LeftSliderLayout.OnLeftSliderLayoutStateListener;

import java.util.ArrayList;
import java.util.List;

/**
 * @author zhiwen.nan
 * @since 1.0
 * 本地视频界面
 */
public class LocalMediaActivity extends BaseActivity {

    private ListView mListView;
    private TextView mTitleText;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.local_media_fragment);

        mListView = (ListView)findViewById(R.id.localVideoList) ;

        mTitleText = (TextView)findViewById(R.id.titleText)  ;
        mTitleText.setText("本地视频");

        Cursor cursor = getContentResolver().query(Contacts.People.CONTENT_URI, null, null, null, null);
        startManagingCursor(cursor);
        ListAdapter listAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_expandable_list_item_1,
                cursor,new String[]{Contacts.People.NAME},new int[]{android.R.id.text1});
        mListView.setAdapter(listAdapter);

    }

    @Override
    public boolean OnLeftSliderLayoutInterceptTouch(MotionEvent ev) {

        return true;
    }

}

LocalMediaActivity是自己定义的Activty和业务逻辑界面,只需继承BaseActivity即可,其他Activity类似。

以上就是核心代码,源代码下载:

时间: 2024-10-20 21:04:52

Android高手进阶篇4-实现侧滑菜单框架,一分钟集成到项目中的相关文章

Android高手进阶教程(二十八)之---Android ViewPager控件的使用(基于ViewPager的横向相册)!!!

分类: Android高手进阶 Android基础教程 2012-09-14 18:10 29759人阅读 评论(35) 收藏 举报 android相册layoutobjectclassloaderencoding 大家好,相信大家用的ListView控件一定很多的,是竖向滑动的,复用convertView,我们可以加载成千上万的数据,但有时候我们会有 这个需求比如相册,我们想横向滑动,并且数据有好多,这时候ViewPager控件就派上用场了,ViewPager使用时候我们需要导入第三方包 an

Android高手进阶——Adapter深入理解与优化

Android高手进阶--Adapter深入理解与优化 通常是针对包括多个元素的View,如ListView,GridView.ExpandableListview,的时候我们是给其设置一个Adapter.Adapter是与View之间提供数据的桥梁,也是提供每一个Item的视图桥梁.   以ListView为例.其工作原理为: ● ListView针对List中每一个item, adapter都会调用一个getView的方法获得布局视图 ●我们通常会Inflate一个新的View,填充数据并返

Elasticsearch顶尖高手系列-高手进阶篇视频教程

14套java精品高级架构课,缓存架构,深入Jvm虚拟机,全文检索Elasticsearch,Dubbo分布式Restful 服务,并发原理编程,SpringBoot,SpringCloud,RocketMQ中间件,Mysql分布式集群,服务架构,运 维架构视频教程 14套精品课程介绍: 1.14套精 品是最新整理的课程,都是当下最火的技术,最火的课程,也是全网课程的精品: 2.14套资 源包含:全套完整高清视频.完整源码.配套文档: 3.知识也 是需要投资的,有投入才会有产出(保证投入产出比是

Android高手进阶教程(十六)之---Android中万能的BaseAdapter(Spinner,ListView,GridView)的使用!

大家好!今天给大家讲解一下BaseAdapter(基础适配器)的用法,适配器的作用主要是用来给诸如(Spinner,ListView,GridView)来填充数据的.而(Spinner,ListView,GridView)都有自己的适配器(记起来麻烦).但是BaseAdapter(一招鲜)对他们来说却是通用的,为什么这么说呢,首先我们看一下API文档: 我们看一下BaseAdapter已经实现了ListAdapter和SpinnerAdapter的接口,而GridView的适配器是实现了List

Elasticsearch顶尖高手系列-高手进阶篇(最新第二版)

第1节结构化搜索_IT技术论坛案例背景介绍第2节结构化搜索_在案例中实战使用termfilter来搜索数据第3节结构化搜索_filter执行原理深度剖析(bitset机制与caching机制)第4节结构化搜索_在案例中实战基于bool组合多个filter条件来搜索数据第5节结构化搜索_在案例中实战使用terms搜索多个值以及多值搜索结果优化第6节结构化搜索_在案例中实战基于rangefilter来进行范围过滤第7节深度探秘搜索技术_在案例中体验如何手动控制全文检索结果的精准度第8节深度探秘搜索技

Android自定义View之仿QQ侧滑菜单实现

最近,由于正在做的一个应用中要用到侧滑菜单,所以通过查资料看视频,学习了一下自定义View,实现一个类似于QQ的侧滑菜单,顺便还将其封装为自定义组件,可以实现类似QQ的侧滑菜单和抽屉式侧滑菜单两种菜单. 下面先放上效果图: 我们这里的侧滑菜单主要是利用HorizontalScrollView来实现的,基本的思路是,一个布局中左边是菜单布局,右边是内容布局,默认情况下,菜单布局隐藏,内容布局显示,当我们向右侧滑,就会将菜单拉出来,而将内容布局的一部分隐藏,如下图所示: 下面我们就一步步开始实现一个

Android 高手进阶,自己定义圆形进度条

背景介绍 在Android 开发中,我们常常遇到各种各样绚丽的控件,所以,依靠我们Android本身所带的控件是远远不够的,许多时候须要我们自定义控件,在开发的过程中.我们公司遇到了一种须要自己写的一个自定义带进度的圆形进度条,看起来很的绚丽,当然另一些其它的.比方:水纹形的圆形进度条等效果都是很nice的.假设哪位朋友有实现,希望分享出来,我也好学习学习. 好了多的不说.接下来,我们就来看看来怎样实现圆形进度条. 原文地址:http://blog.csdn.net/xiaanming/arti

Android 高手进阶,自定义圆形进度条

背景介绍 在Android 开发中,我们经常遇到各种各样绚丽的控件,所以,依靠我们Android本身所带的控件是远远不够的,很多时候需要我们自己定义控件,在开发的过程中,我们公司遇到了一种需要自己写的一个自定义带进度的圆形进度条,看起来非常的绚丽,当然还有一些其他的,比如:水纹形的圆形进度条等效果都是非常nice的.如果哪位朋友有实现,希望分享出来,我也好学习学习.好了多的不说,接下来,我们就来看看来如何实现圆形进度条. 原文地址:http://blog.csdn.net/xiaanming/a

Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)

转载请注明地址:http://blog.csdn.net/xiaanming/article/details/10298163 很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如onDraw,为了我们自定义的View在一个项目中能够重用,有时候我们需要自定义其属性,举个很简单的例子,我在项目中的多个界面使用我自定义的View,每个界面该自定义View