Android开发项目实战:实现折叠式布局

简介:

首先实现一个头部固定的ExpandedListView,然后在它的基础上实现:在头部加一个背景图片,默认状态下他处于展开状态,往上滑的时候背景图片逐渐的折叠起来,往下滑的时候背景图片慢慢的展开效果图如下:

通过CoordinateLayout实现的折叠式布局

有人可能会说这不就是折叠式布局吗?是的,这就是Android 5.0给我们提供的材料设计库中的CoordinateLayout就是解决这个问题的,使用CoordinateLayout来协调ScrollView,NestedScrollView,ListView,RecycleView和顶部的背景图片、ToolBar之间的滚动关系、在很多的手机应用中,时不时会看到关于折叠布局的效果,现在我们先看看CoordinateLayout是怎么实现的然后在讲我们自定义实现一个折叠式布局,直接上代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="200dp">

        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:titleEnabled="false">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@mipmap/homepage_pic_banner"
                app:layout_collapseMode="parallax" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/view_toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:text="新闻详情" />
            </android.support.v7.widget.Toolbar>
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:text="hello world" />
            ...
            ...
        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

image

以上就是实现一个折叠式布局的典型模板布局代码,一个简简单单的布局就实现了这样的效果,但是必须要注意在AndroidMnifest.xml必须要给Activity指定它的theme为NoActionBar的样式代码如下:

 <activity
            android:name=".test.CoordinatorLayoutTestActivity"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>

否则会出现ActionBar和ToolBar共存的情况,的显示效果如下:

另外还需要把自己自定义的ToolBar告诉给系统,即第9行的setSupportActionBar(toolbar),否则我们的ToolBar会作为一个普通的View而存在

public class CoordinatorLayoutTestActivity extends AppCompatActivity {

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_coordinator_layout_test);
        Toolbar toolbar = findViewById(R.id.view_toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayShowTitleEnabled(false);
        toolbar.setNavigationIcon(R.mipmap.callback_white_icon);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onBackPressed();
            }
        });
    }
}

如果只指定了 setSupportActionBar(toolbar),没有AndroidMnifest.xml在指定Activity的theme为NoActionBar,那就运行就直接崩溃了,会报错如下:

 Caused by: java.lang.IllegalStateException: This Activity already has an action bar supplied by the window decor. Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set windowActionBar to false in your theme to use a Toolbar instead.
        at android.support.v7.app.AppCompatDelegateImpl.setSupportActionBar(AppCompatDelegateImpl.java:345)
        at android.support.v7.app.AppCompatActivity.setSupportActionBar(AppCompatActivity.java:130)

意思是说Activity已经有一个ActionBar了,请在你的样式中使用ToolBar替代

在上面的布局文件代码中,根布局CoordinatorLayout 就是用来协调AppBarLayout和NestedScrollView之间滚动的,40行的NestedScrollView是我们要滚动的内容,在11行的CollapsingToolbarLayout标签的内部就是要折叠的内容

  • 其中43行的 app:layout_behavior不配置的效果:

    ![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy8xNTM0MjU0MS0wODNjNDhmMWM5OWRkNTk2LmdpZj9pbWFnZU1vZ3IyL2F1dG8tb3JpZW50L3N0cmlwfGltYWdlVmlldzIvMi93LzM2MC9mb3JtYXQvd2VicA)
    
    NestedScrollView的内容在ToolBar之上滚动
    
  • 其中13行app:layout_scrollFlags="scroll|exitUntilCollapsed"如果不配置效果图如下:

    ![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy8xNTM0MjU0MS02MTlhZThjOTQyZWEwODBkLmdpZj9pbWFnZU1vZ3IyL2F1dG8tb3JpZW50L3N0cmlwfGltYWdlVmlldzIvMi93LzM2MC9mb3JtYXQvd2VicA)
    
    如果没有配置则CollapsingToolbarLayout包裹内容内容就会固定在顶部,不会滚动
    
  • 28行 app:layout_collapseMode="pin"不配置,效果图:

    ![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy8xNTM0MjU0MS1kN2NkMGM1NWEyYmNiYmUyLmdpZj9pbWFnZU1vZ3IyL2F1dG8tb3JpZW50L3N0cmlwfGltYWdlVmlldzIvMi93LzM2MC9mb3JtYXQvd2VicA)
    
    ToolBar会跟随NestedScrollView的滚动而滚动,而不会固定在布局顶部位置
    
  • 14行app:titleEnabled="false"不配置,效果图:

    ![image](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy8xNTM0MjU0MS03MmUyNzEwMGYxY2U4MmU2LmdpZj9pbWFnZU1vZ3IyL2F1dG8tb3JpZW50L3N0cmlwfGltYWdlVmlldzIvMi93LzM2MC9mb3JtYXQvd2VicA)
    
    即使33行的TextView配置了android:layout_gravity="center",title也不会居中显示
    

我们感觉折叠式布局就是给我们的View设置相关的属性配置,不需要进行任何编码就能完成我们的折叠效果,我们不得的赞叹android 5.0给我们提供这一强大的功能

我们来总结一下:
CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout结合起来才能产生这么神奇的效果,不要幻想使用其中的一个控件就能完成这样的效果

ToolBar的设置

系统默认使用的就是系统自带的ActionBar,如果我们要使用自定义的ToolBar,就必须明确的告诉Activity不需要使用系统自带的ActionBar即要给activity设置NoActionBar的样式,另外必须调用setSupportActionBar(toolbar)将自己定义的ToolBar设置给Activity。

CoordinatorLayout下可滑动控件的设置

CoordinatorLayout作为整个布局的父布局容器。给你的可以滑动的控件例如RecyclerView设置如下属性:app:layout_behavior=@string/appbar_scrolling_view_behavior
CoordinatorLayout还提供了layout_anchor 和 layout_anchorGravity属性一起配合使用,可以用于设置FloatingActionButton的位置,此处我是放在appBar的右下角。
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|right|end"

CollapsingToolbarLayout的layout_scrollFlags属性

AppBarLayout里面定义的子view只要设置了app:layout_scrollFlags属性,就可以在RecyclerView滚动事件发生的时候被触发某种行为
例如我给CollapsingToolbarLayout控件设置了 app:layout_scrollFlags="scroll|exitUntilCollapsed"此刻如果没有这个属性,CollapsingToolbarLayout是不会折叠的那么问题来了,layout_scrollFlags中的属性值除了可以触发折叠的行为,还有其它的属性值吗?并且各个属性的意义是什么?scroll至少有一个scroll,即可滚动。

属性 作用
scroll 必须要给其至少有设置一个scroll,即可滚动
enterAlways 向下滚动即可见。例如下拉时,立即显示Toolbar
exitUntilCollapsed 这个flag是定义何时收缩。当你定义了一个minHeight,这个view将在滚动到达这个最小高度的时候消失
enterAlwaysCollapsed 这个flag是定义何时展开。当你定义了一个最小高度minHeight, 同时enterAlways也定义了,那么view将在到达这个最小高度的时候开始展示
snap 当一个滚动事件结束,它将根据显示百分比的大小自动滚动到收缩或展开。

如果不设置该属性,则该布局不能滑动

CollapsingToolbarLayout的其他属性

另外还可以给CollapsingToolbarLayout设置以下属性:

属性 作用
contentScrim 设置当完全折叠(收缩)后的背景颜色。
expandedTitleMarginEnd 没有扩张的时候标题显示的位置
expandedTitleMarginStart 扩张的时候标题向左填充的距离。
statusBarScrim 设置折叠时状态栏的颜色

CollapsingToolbarLayout下的view的layout_collapseMode属性

CollapsingToolbarLayout里面定义的view只要设置了app:layout_collapseMode属性,就可以控制子视图的折叠模式。
折叠模式分为两种:

属性 作用
pin 固定模式。在收缩的时候最后固定在顶端(例如向上滚动的时候就固定toolBar)
parallax 视差模式,在折叠的时候会有个视差折叠的效果。(例如向下滚动的时候就展开ImageView)

CoordinatorLayout 的fitsSystemWindows属性

fitsSystemWindows属性可以让view根据系统窗口来调整自己的布局,简单点说就是我们在设置应用布局时是否考虑系统窗口布局,这里系统窗口包括系统状态栏、导航栏、输入法等,包括一些手机系统带有的底部虚拟按键。android:fitsSystemWindows=”true” (触发View的padding属性来给系统窗口留出空间) 这个属性可以给任何view设置,只要设置了这个属性此view的其他所有padding属性失效,同时该属性的生效条件是只有在设置了透明状态栏(StatusBar)或者导航栏(NavigationBar)此属性才会生效

如何监听CollapsingToolbarLayout的展开与折叠

使用官方提供的 AppBarLayout.OnOffsetChangedListener就能实现了,不过要封装一下才好用,自定义一个继承了 AppBarLayout.OnOffsetChangedListener的类这里命名为AppBarStateChangeListener

public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener {

    public enum State {
        EXPANDED,
        COLLAPSED,
        IDLE
    }
    private State mCurrentState = State.IDLE;

    @Override
    public final void onOffsetChanged(AppBarLayout appBarLayout, int i) {
        if (i == 0) {
            if (mCurrentState != State.EXPANDED) {
                onStateChanged(appBarLayout, State.EXPANDED);
            }
            mCurrentState = State.EXPANDED;
        } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) {
            if (mCurrentState != State.COLLAPSED) {
                onStateChanged(appBarLayout, State.COLLAPSED);
            }
            mCurrentState = State.COLLAPSED;
        } else {
            if (mCurrentState != State.IDLE) {
                onStateChanged(appBarLayout, State.IDLE);
            }
            mCurrentState = State.IDLE;
        }
    }
    public abstract void onStateChanged(AppBarLayout appBarLayout, State state);
}

然后我们这样使用它:

 mAppBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() {
            @Override
            public void onStateChanged(AppBarLayout appBarLayout, State state) {
                Log.d("STATE", state.name());
                if( state == State.EXPANDED ) {
                     //展开状态                    
                }else if(state == State.COLLAPSED){
                    //折叠状态                     
                }else {                
                    //中间状态                
                }
            }
        });

这样就可以在不同的状态下根据自己的业务需求去实现相关的逻辑了

StickyLayout自定折叠式布局的实现

好了,上面就是关于通过CoordinateLayout实现的折叠式布局所有的知识点,如果说前面只是开胃菜,现在我们就开始上主菜了,我们能不能自己实现这样一个折叠式的布局,利用上一篇我们所讲的头部固定的ExpandedListView,把它作为具有滑动功能的主View,在它的顶部添加具有背景图片Header,随着ExpandedListView的滑动header实现扩展和收缩的效果,效果如下:

功能分析

其实这个效果图在文章的一开始就展示过了,整个布局分为上下两部分:上分部分为可折叠的Header,下半部分就是我们头部固定的ExpandedListView,他们公共父view就是今天我们要实现的折叠式布局StickyLayout,ExpandedListView是自身所具备滑动功能的,而我们在整个屏幕上,往上滑动的时候如果header处于展开状态则Header慢慢的要折叠起来,往下滑动的时候如果ExpandedListView顶部数据都显示出来的情况下再往下拉的时候Header就慢慢的展开,其他的状态就是我们的ExpandedListView在上下滑动,也就是说我们的Header在折叠和展开的状态下的这些事件被StickyLayout拦截了,其他的事件就交给ExpandedListView进行处理从而实现了他的上下滑动,这就属于典型的滑动冲突问题,简言之就是我们在上下滑动的过程中的有些事件需要被StickyLayout拦截消掉来实现Header的折叠和展开效果,其他的事件就交给ExpandedListView来实现它的滑动效果
现在我们要思考的是哪些情况下被拦截:

  • 左右滑动的不需要处理,只处理上下滑动的事件
  • 在展开的状态下,上滑事件需要拦截
  • ExpandedListView的第0个元素处于可见状态,此时的下滑事件需要拦截

在事件拦截方法中处理滑动冲突

public class StickyLayout extends LinearLayout {
    ...
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean intercept = false;
        int x = (int) ev.getX();
        int y = (int) ev.getY();
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                mLastInterceptX = x;
                mLastInterceptY = y;
                intercept = false;
                break;
            case MotionEvent.ACTION_MOVE:
                int dx = x - mLastInterceptX;
                int dy = y - mLastInterceptY;
                if(y <= mCurrHeaderHeight){
                    intercept = false;
                }else if(Math.abs(dx) > Math.abs(dy)){
                    intercept = false;
                }else if(mState == mStateExpand && dy <= - mScaledTouchSlop){
                    //上滑
                    intercept = true;
                }else if(mGiveUpTouchEventListener.giveUpTouchEvent() && dy > mScaledTouchSlop){
                    //下滑
                    intercept = true;
                }else{
                    intercept = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                mLastInterceptX = 0;
                mLastInterceptY = 0;
                intercept = false;
                break;
        }
        return intercept;
    }
    ...
}

上面就是关于事件拦截的核心代码,首先我们看17行:y <= mCurrHeaderHeight 如果触摸事件是在Header之上也就不拦截了,再看19行Math.abs(dx) > Math.abs(dy),如果是横向滑动也不是我们所需要的事件也不拦截,否则上就是上下滑动的事件了,在这个状态下状态Header处于展开状态且是上滑那就需要拦截处理,也就是21行:mState == mStateExpand && dy <= - mScaledTouchSlop所处理的逻辑,在看24行:mGiveUpTouchEventListener.giveUpTouchEvent() && dy > mScaledTouchSlop,giveUpTouchEvent方法表示如果ExpandedListView的第一个可见元素是0且dy > mScaledTouchSlop(表示是上滑)此时的事件也是需要拦截的

View滑动距离常量TouchSlop

在21行细心的同学可能会看到这么一句dy <= - mScaledTouchSlop,dy指的是滑动的距离,mScaledTouchSlop到底是什么?其实他是Android系统给我们提供的View滑动最小距离常量TouchSlop,也就是说两个Move事件之间的滑动距离如果小于这个常量就系统不认为他是滑动,因为滑动距离太短,反之就认为它是滑动,这个常量值和设备有关,不同的设置上这个值可能是不相同的,我们可以通过如下方式即可获取这个常量:

int mScaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

折叠展开的事件消费

上面的17到29行就是处理事件拦截的核心处理逻辑,事件拦截完毕,事件就交给TouchEvent方法进行消费了,下面看看Header到底具体是怎么折叠的?其实很简单就是不用重置Header的height就OK了,我们看看代码:

public class StickyLayout extends LinearLayout {
    ...
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                int dx = x - mLastX;
                int dy = y - mLastY;
                mCurrHeaderHeight += dy;
                setHeaderHeight(mCurrHeaderHeight);
                break;
            case MotionEvent.ACTION_UP:
                int dest = 0;
                if(mCurrHeaderHeight <= mOriginHeaderHeight * 0.5){
                    dest = 0;
                    mState = mStateCollapsed;
                }else{
                    dest = mOriginHeaderHeight;
                    mState = mStateExpand;
                }
                smoothSetHeaderHeight(mCurrHeaderHeight,dest,500);
                break;
        }
        mLastX = x;
        mLastY = y;
        return super.onTouchEvent(event);
    }
    ...
}

其中12行到13行就是手指拖动状态下的核心逻辑 ,12行计算两次Move事件所移动的距离,13行根据手指滑动的距离来计算Header当前的高度,计算完毕就可以调用setHeaderHeight设置Header的高了

设置Header的高来实现折叠效果

private void setHeaderHeight(int height) {
        if(height <= 0){
            height = 0;
        }else if(height >= mOriginHeaderHeight){
            height = mOriginHeaderHeight;
        }
        if(height == 0 ){
            mState = mStateCollapsed;
        }else{
            mState = mStateExpand;
        }
        headerView.getLayoutParams().height = height;
        headerView.requestLayout();
    }

其中第2行到第6行对Header高度的越界处理,第7行到11行是设置Header的状态,第12行到13行给Header的高赋值并刷新Header来变它的位置与大小

手指抬起的自动回弹折叠展开效果

如果当前Header的高小于原始高度的一半手指抬起的时候Header进行收缩,反之就进行展开操作,核心代码在上面的onTouchEvent(MotionEvent event)方法的的17行到25行:

  int dest = 0;
  if(mCurrHeaderHeight <= mOriginHeaderHeight * 0.5){
        dest = 0;
        mState = mStateCollapsed;
  }else{
        dest = mOriginHeaderHeight;
        mState = mStateExpand;
   }
  smoothSetHeaderHeight(mCurrHeaderHeight,dest,500);

最后在调用smoothSetHeaderHeight实现弹性展开,折叠

    private void smoothSetHeaderHeight(int from,int to,int duration) {
       ValueAnimator valueAnimator = ValueAnimator.ofInt(from, to).setDuration(duration);
       valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
           @Override
           public void onAnimationUpdate(ValueAnimator animation) {
               setHeaderHeight((Integer) animation.getAnimatedValue());
           }
       });
       valueAnimator.start();
   }

总结

截止目前整个折叠式自定义View就全部讲完了,事件拦截这块的判断逻辑是整个代码的核心,找到了判断折叠、展开的的算法那么其他的问题也就不是什么大问题了,解决滑动冲突问题也是我们在自定义View开发过程中的常见问题,也是难点问题,只要多练习,多思考就能孰能生巧最后我将整个测试代码传到了github上,欢迎学习下载https://github.com/mxdldev/android-custom-view/,其中StickyLayout.java就是我们本例中的自定义View的全部代码实现,下载完整项目后直接运行安装完毕,点击StickyLayout按钮就进入了我们的测试页面,效果图如下:

作者:门心叼龙
链接:https://www.jianshu.com/p/1ba947bc0a98

相关文章
|
22天前
|
ARouter Android开发
Android不同module布局文件重名被覆盖
Android不同module布局文件重名被覆盖
|
6天前
|
编解码 Java Android开发
通义灵码:在安卓开发中提升工作效率的真实应用案例
本文介绍了通义灵码在安卓开发中的应用。作为一名97年的聋人开发者,我在2024年Google Gemma竞赛中获得了冠军,拿下了很多项目竞赛奖励,通义灵码成为我的得力助手。文章详细展示了如何安装通义灵码插件,并通过多个实例说明其在适配国际语言、多种分辨率、业务逻辑开发和编程语言转换等方面的应用,显著提高了开发效率和准确性。
|
5天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
18 5
|
3天前
|
JSON Java Android开发
探索安卓开发之旅:打造你的第一个天气应用
【10月更文挑战第30天】在这个数字时代,掌握移动应用开发技能无疑是进入IT行业的敲门砖。本文将引导你开启安卓开发的奇妙之旅,通过构建一个简易的天气应用来实践你的编程技能。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你宝贵的学习资源。我们将一步步地深入到安卓开发的世界中,从搭建开发环境到实现核心功能,每个环节都充满了发现和创造的乐趣。让我们开始吧,一起在代码的海洋中航行!
|
5天前
|
缓存 数据库 Android开发
安卓开发中的性能优化技巧
【10月更文挑战第29天】在移动应用的海洋中,性能是船只能否破浪前行的关键。本文将深入探讨安卓开发中的性能优化策略,从代码层面到系统层面,揭示如何让应用运行得更快、更流畅。我们将以实际案例和最佳实践为灯塔,引领开发者避开性能瓶颈的暗礁。
16 3
|
7天前
|
存储 IDE 开发工具
探索Android开发之旅:从新手到专家
【10月更文挑战第26天】在这篇文章中,我们将一起踏上一段激动人心的旅程,探索如何在Android平台上从零开始,最终成为一名熟练的开发者。通过简单易懂的语言和实际代码示例,本文将引导你了解Android开发的基础知识、关键概念以及如何实现一个基本的应用程序。无论你是编程新手还是希望扩展你的技术栈,这篇文章都将为你提供价值和启发。让我们开始吧!
|
13天前
|
Java API Android开发
安卓应用程序开发的新手指南:从零开始构建你的第一个应用
【10月更文挑战第20天】在这个数字技术不断进步的时代,掌握移动应用开发技能无疑打开了一扇通往创新世界的大门。对于初学者来说,了解并学习如何从无到有构建一个安卓应用是至关重要的第一步。本文将为你提供一份详尽的入门指南,帮助你理解安卓开发的基础知识,并通过实际示例引导你完成第一个简单的应用项目。无论你是编程新手还是希望扩展你的技能集,这份指南都将是你宝贵的资源。
42 5
|
12天前
|
设计模式 IDE Java
探索安卓开发:从新手到专家的旅程
【10月更文挑战第22天】 在数字时代的浪潮中,移动应用开发如同一座金矿,吸引着无数探险者。本文将作为你的指南针,指引你进入安卓开发的广阔天地。我们将一起揭开安卓平台的神秘面纱,从搭建开发环境到掌握核心概念,再到深入理解安卓架构。无论你是初涉编程的新手,还是渴望进阶的开发者,这段旅程都将为你带来宝贵的知识和经验的财富。让我们开始吧!
|
16天前
|
缓存 前端开发 Android开发
Android实战之如何截取Activity或者Fragment的内容?
本文首发于公众号“AntDream”,介绍了如何在Android中截取Activity或Fragment的屏幕内容并保存为图片。包括截取整个Activity、特定控件或区域的方法,以及处理包含RecyclerView的复杂情况。
15 3
|
20天前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
66 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库