Android 布局动画之 animateLayoutChanges 与 LayoutTransition

   2016-09-18 0
核心提示:关于布局动画是针对ViewGroup而言的,意指ViewGroup在增加子View或者删除子View时其子View的过渡动画,在android官网有这么一个简单的例子,其效果如下,接下来我们就通过这个例子来入门最简单的布局动画实现 事实上,实现上面ViewGroup的布局动画非常简单,

关于布局动画是针对ViewGroup而言的,意指ViewGroup在增加子View或者删除子View时其子View的过渡动画,在android官网有这么一个简单的例子,其效果如下,接下来我们就通过这个例子来入门

最简单的布局动画实现

事实上,实现上面ViewGroup的布局动画非常简单,我们只要给子View所在的ViewGroup的xml中添加下面的属性即可:

android:animateLayoutChanges="true"

通过设置以上代码,当ViewGroup在添加View时,子View会呈现出过渡的动画效果,这个动画效果是android默认的显示效果,而且无法使用自定义的动画来替换这个效果,不过还是有其他方式可以实现自定义的过渡动画滴,这个我们后面会分析,下面看看android官方给的demo的代码实现:

activity_layout_changes.xml布局文件

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- A vertical LinearLayout in a ScrollView. This emulates a ListView (and is lighter weight
         than a ListView when there aren't many rows). -->
    <ScrollView android:layout_width="match_parent"
        android:layout_height="match_parent">

        <!-- Note that this LinearLayout has the "animateLayoutChanges" property set to true.
             This tells the framework to automatically animate child views (in this case, rows)
             as they are added to and removed from the LinearLayout. -->
        <LinearLayout android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:showDividers="middle"
            android:divider="?android:dividerHorizontal"
            android:animateLayoutChanges="true"
            android:paddingLeft="16dp"
            android:paddingRight="16dp" />

    </ScrollView>

    <!-- The "empty" view to show when there are no items in the "list" view defined above. -->
    <TextView android:id="@android:id/empty"
        style="?android:textAppearanceSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:padding="32dp"
        android:text="@string/message_empty_layout_changes"
        android:textColor="?android:textColorSecondary" />

</FrameLayout>

布局代码比较简单,使用了一个ScrollView包裹了LinearLayout布局并在LinearLayout中添加了属性 android:animateLayoutChanges="true" ,启动了android自带的布局动画,之所以使用ScrollView,是为了在添加子View多时可以进行滑动,而TextView只不过在没有子view时一个提示语。接着看看子View的布局文件list_item_example.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="?android:listPreferredItemHeightSmall"
    android:orientation="horizontal"
    android:showDividers="middle"
    android:divider="?android:dividerVertical"
    android:dividerPadding="8dp"
    android:gravity="center">

    <!-- Dummy text view that will display the name of a random country. -->
    <TextView android:id="@android:id/text1"
        style="?android:textAppearanceMedium"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:paddingLeft="?android:listPreferredItemPaddingLeft" />

    <!-- A button that, when pressed, will delete this list item row from its container. -->
    <ImageButton android:id="@+id/delete_button"
        android:layout_width="48dp"
        android:layout_height="match_parent"
        android:src="@drawable/ic_list_remove"
        android:background="?android:selectableItemBackground"
        android:contentDescription="@string/action_remove_item" />

</LinearLayout>

主要控件有用于显示每个子View内容的TextView和用于响应删除子View事件的ImageButton,最后就是Activity的实现:

LayoutChangesActivity.java

package com.example.android.animationsdemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * This sample demonstrates how to use system-provided, automatic layout transitions. Layout
 * transitions are animations that occur when views are added to, removed from, or changed within
 * a {@link ViewGroup}.
 *
 * <p>In this sample, the user can add rows to and remove rows from a vertical
 * {@link android.widget.LinearLayout}.</p>
 */
public class LayoutChangesActivity extends Activity {

    private ViewGroup mContainerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_layout_changes);

        mContainerView = (ViewGroup) findViewById(R.id.container);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        //响应添加事件的menu
        getMenuInflater().inflate(R.menu.activity_layout_changes, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class));
                return true;

            case R.id.action_add_item:
                //添加子View
                findViewById(android.R.id.empty).setVisibility(View.GONE);
                addItem();
                return true;
        }

        return super.onOptionsItemSelected(item);
    }

    private void addItem() {
        //实例化一个子View
        final ViewGroup newView = (ViewGroup) LayoutInflater.from(this).inflate(
                R.layout.list_item_example, mContainerView, false);

        // 随机设置子View的内容
        ((TextView) newView.findViewById(android.R.id.text1)).setText(
                COUNTRIES[(int) (Math.random() * COUNTRIES.length)]);

        //设置删除按钮的监听
        newView.findViewById(R.id.delete_button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mContainerView.removeView(newView);

                // If there are no rows remaining, show the empty view.
                if (mContainerView.getChildCount() == 0) {
                    findViewById(android.R.id.empty).setVisibility(View.VISIBLE);
                }
            }
        });
        //添加子View
        mContainerView.addView(newView, 0);
    }

    /**
     * A static list of country names.
     */
    private static final String[] COUNTRIES = new String[]{
            "Belgium", "France", "Italy", "Germany", "Spain",
            "Austria", "Russia", "Poland", "Croatia", "Greece",
            "Ukraine",
    };
}

代码比较简单,mContainerView作为子View的承载容器,我们可以不断添加子View,也可以移除子View,由于我们在布局文件中启动了android自带的布局动画,所以在添加子View或移除子View都会有过度动画,现在运行程序,效果如下:

这就是android中最简单的布局动画

布局动画实之layoutAnimation

除了上面的布局动画外,有时我们可能需要第一次加载ListView或者GridView的时候能有个动画的过度效果,以便达到更好的体验,如下ListView加载子View的效果:

事实上实现这种效果也比较简单,我们只需要在ListView的布局文件中添加android:layoutAnimation=”@anim/layout”属性即可。接下来给出实现步骤:

实现动画效果

left_into.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="500"
        android:fromXDelta="100%"
        android:fromYDelta="0"
        android:toXDelta="0"
        android:toYDelta="0" />
    <alpha
        android:duration="500"
        android:fromAlpha="0"
        android:toAlpha="1" />
</set>

这个比较简单,就一个平移和透明度的效果,接着创建layout_animation.xml

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/left_into"
    android:animationOrder="normal"
    android:delay="0.5"
    />

这里简单介绍一下layoutAnimation标签属性:

属性名 含义
android:delay delay的单位为秒,表示子View进入的延长时间
android:animationOrder 子类的进入方式 ,其取值有,normal 0 默认 ,reverse 1 倒序 ,random 2 随机
android:animation 子view要执行的具体动画的文件,自定义即可

然后设置给listView控件即可,activity_listview.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 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"
        <!-- 设置在这里 :arrow_down::arrow_down::arrow_down::arrow_down::arrow_down::arrow_down::arrow_down::arrow_down::arrow_down::arrow_down: -->
        android:layoutAnimation="@anim/layout_animation"
        >
    </ListView>
</LinearLayout>

ListViewActivity.java代码如下:

package com.example.android.animationsdemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

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

/**
 * Created by zejian
 * Time 16/9/17.
 * Description:
 */
public class ListViewActivity extends Activity {

    private ListView listView;
    private List<String> list;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_listview);
        listView= (ListView) findViewById(R.id.listView);
        initData();
        listView.setAdapter(new Myadpter());
    }

    public void initData(){
        list = new ArrayList<>();
        for(int i=1;i<30;i++){
            list.add("布局动画listView测试_"+i);
        }
    }

    private  class  Myadpter extends BaseAdapter{

        @Override
        public int getCount() {
            return list.size();
        }

        @Override
        public Object getItem(int position) {
            return list.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            TextView tv= new TextView(ListViewActivity.this);
            tv.setTextSize(20);
            tv.setHeight(100);
            tv.setText(list.get(position));
            return tv;
        }
    }
}

执行以上代码,效果就是前面我们给出listView进入的动态效果,这里特别注意的是,动画只在listView子View第一次进入时有效,如果后面动态给listView添加子View时,此动画效果无效,当然除了通过xml设置外,我们还可以通过代码动态设置,代码范例如下,这里就不演示了。

//通过加载XML动画设置文件来创建一个Animation对象,子View进入的动画
Animation animation=AnimationUtils.loadAnimation(this, R.anim.left_into);
//得到一个LayoutAnimationController对象;
LayoutAnimationController lac=new LayoutAnimationController(animation);
//设置控件显示的顺序;
lac.setOrder(LayoutAnimationController.ORDER_REVERSE);
//设置控件显示间隔时间;
lac.setDelay(0.5f);
//为ListView设置LayoutAnimationController属性;
listView.setLayoutAnimation(lac);

通过AnimationUtils.loadAnimation加载子View的动画来并返回一个Animation对象,然后将Animation对象设置到LayoutAnimationController中并返回LayoutAnimationController对象,配置LayoutAnimationController对象的一些属性,最后设置到ListView中,其中LayoutAnimationController对应layoutAnimation标签,这里需要注意的是layoutAnimation动画不仅仅限于ListView,GridView中,也可用于一切ViewGroup中。

布局动画实之LayoutTransition

前面我们说过ViewGroup在设置 android:animateLayoutChanges="true" 后在添加或者删除子view时可以启用系统带着的动画效果,但这种效果无法通过自定义动画去替换。不过还好android官方为我们提供了LayoutTransition类,通过LayoutTransition就可以很容易为ViewGroup在添加或者删除子view设置自定义动画的过渡效果了。

LayoutTransition类用于当前布局容器中需要View添加,删除,隐藏,显示时设置布局容器子View的过渡动画。也就是说利用LayoutTransition,可以分别为需添加或删除的View对象在移动到新的位置的过程添加过渡的动画效果。我们可以通过setLayoutTransition()方法为布局容器ViewGroup设置LayoutTransition对象,代码如下:

//初始化容器动画
LayoutTransition mTransitioner = new LayoutTransition();
container.setLayoutTransition(mTransitioner);

一般地,Layout中的子View对象有四种动画变化的形式,如下:

属性值 含义
LayoutTransition.APPEARING 子View添加到容器中时的过渡动画效果。
LayoutTransition.CHANGE_APPEARING 子View添加到容器中时,其他子View位置改变的过渡动画
LayoutTransition.DISAPPEARING 子View从容器中移除时的过渡动画效果。
LayoutTransition.CHANGE_DISAPPEARING 子View从容器中移除时,其它子view位置改变的过渡动画
LayoutTransition.CHANGING 子View在容器中位置改变时的过渡动画,不涉及删除或者添加操作

下面给出一个例子,先看布局文件activity_layout_animation.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="addView"
            android:text="添加控件" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="removeView"
            android:text="移除控件" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" />
</LinearLayout>

比较简单不啰嗦,接着看看LayoutAnimationActivity.java

package com.example.android.animationsdemo;

import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;

/**
 * Created by zejian
 * Time 16/9/17.
 * Description:
 */
public class LayoutAnimationActivity extends Activity {


    private int i = 0;
    private LinearLayout container;
    private LayoutTransition mTransitioner;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_layout_animation);

        container = (LinearLayout) findViewById(R.id.container);
        //构建LayoutTransition
        mTransitioner = new LayoutTransition();
        //设置给ViewGroup容器
        container.setLayoutTransition(mTransitioner);
        setTransition();
    }


    private void setTransition() {
        /**
         * 添加View时过渡动画效果
         */
        ObjectAnimator addAnimator = ObjectAnimator.ofFloat(null, "rotationY", 0, 90,0).
                setDuration(mTransitioner.getDuration(LayoutTransition.APPEARING));
        mTransitioner.setAnimator(LayoutTransition.APPEARING, addAnimator);

        /**
         * 移除View时过渡动画效果
         */
        ObjectAnimator removeAnimator = ObjectAnimator.ofFloat(null, "rotationX", 0, -90, 0).
                setDuration(mTransitioner.getDuration(LayoutTransition.DISAPPEARING));
        mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, removeAnimator);

        /**
         * view 动画改变时,布局中的每个子view动画的时间间隔
         */
        mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
        mTransitioner.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 30);


        /**
         *LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING的过渡动画效果
         * 必须使用PropertyValuesHolder所构造的动画才会有效果,不然无效!使用ObjectAnimator是行不通的,
         * 发现这点时真特么恶心,但没想到更恶心的在后面,在测试效果时发现在构造动画时,”left”、”top”、”bottom”、”right”属性的
         * 变动是必须设置的,至少设置两个,不然动画无效,问题是我们即使这些属性不想变动!!!也得设置!!!
         * 我就问您恶不恶心!,因为这里不想变动,所以设置为(0,0)
         *
         */
        PropertyValuesHolder pvhLeft =
                PropertyValuesHolder.ofInt("left", 0, 0);
        PropertyValuesHolder pvhTop =
                PropertyValuesHolder.ofInt("top", 0, 0);
        PropertyValuesHolder pvhRight =
                PropertyValuesHolder.ofInt("right", 0, 0);
        PropertyValuesHolder pvhBottom =
                PropertyValuesHolder.ofInt("bottom", 0, 0);


        /**
         * view被添加时,其他子View的过渡动画效果
         */
        PropertyValuesHolder animator = PropertyValuesHolder.ofFloat("scaleX", 1, 1.5f, 1);
        final ObjectAnimator changeIn = ObjectAnimator.ofPropertyValuesHolder(
                this, pvhLeft,  pvhBottom, animator).
                setDuration(mTransitioner.getDuration(LayoutTransition.CHANGE_APPEARING));
        //设置过渡动画
        mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING, changeIn);


        /**
         * view移除时,其他子View的过渡动画
         */
        PropertyValuesHolder pvhRotation =
                PropertyValuesHolder.ofFloat("scaleX", 1, 1.5f, 1);
        final ObjectAnimator changeOut = ObjectAnimator.ofPropertyValuesHolder(
                this, pvhLeft, pvhBottom, pvhRotation).
                setDuration(mTransitioner.getDuration(LayoutTransition.CHANGE_DISAPPEARING));

        mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeOut);
    }


    public void addView(View view) {
        i++;
        Button button = new Button(this);
        button.setText("布局动画_" + i);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        container.addView(button, Math.min(1, container.getChildCount()), params);
    }

    public void removeView(View view) {
        if (i > 0)
            container.removeViewAt(0);
    }
}

简单分析一下,LayoutTransition.APPEARING和LayoutTransition.DISAPPEARING的情况下直接使用属性动画来设置过渡动画效果即可,而对于LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必须使用PropertyValuesHolder所构造的动画才会有效果,不然无效,真特么恶心, ,但没想到更恶心的在后面,在测试效果时发现在构造动画时,”left”、”top”、”bottom”、”right”属性的变动是必须设置的,至少设置两个,不然动画无效,最坑爹的是我们即使这些属性不想变动!!!也得设置!!!我就问您恶不恶心!,那么我们不想改变这四个属性时该如何设置呢?这时只要传递的可变参数都一样就行如下面的(0,0)也可以是(100,100)即可(坑爹啊!测试半天才发现,一直在考虑代码有没有问题,最后发现时特么的也是醉了…….):

PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",0,0);  
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("left",100,100);  
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("bottom",0,0);  
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("right",0,0);

还有点需要注意的是在使用的ofInt,ofFloat中的可变参数值时,第一个值和最后一个值必须相同,不然此属性将不会有动画效果,比如下面首位相同是有效的

PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",100,0,100);
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",0,100,0);

但是如果是下面的设置就是无效的:

PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("left",0,100);

关于PropertyValuesHolder,后面我会分开单独一篇来分析,这里我们只需知道PropertyValuesHolder构造的动画可以设置给ObjectAnimator.ofPropertyValuesHolder()便可以产生响应的动画效果即可,该方法原型如下:

public static ObjectAnimator ofPropertyValuesHolder(Object target, PropertyValuesHolder... values)

最后我们通过setAniamtor的方法设置LayoutTransition的5种状态下的过渡动画,最后运行一下程序,效果如下:

最后这里小结一下LayoutTransition的一些常用函数:

函数名称 说明
setAnimator(int transitionType, Animator animator) 设置不同状态下的动画过渡,transitionType取值为, APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING 、CHANGING
setDuration(long duration) 设置所有动画完成所需要的时长
setDuration(int transitionType, long duration) 设置特定type类型动画时长,transitionType取值为, APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING 、CHANGING
setStagger(int transitionType, long duration) 设置特定type类型动画的每个子item动画的时间间隔 ,transitionType取值为: APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING、CHANGING
setInterpolator(int transitionType, TimeInterpolator interpolator) 设置特定type类型动画的插值器, transitionType取值为: APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING、CHANGING
setStartDelay(int transitionType, long delay) 设置特定type类型动画的动画延时 transitionType取值为, APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING 、CHANGING
addTransitionListener(TransitionListener listener) 设置监听器TransitionListener

关于监听器接口TransitionListener原型如下:

/**
 * This interface is used for listening to starting and ending events for transitions.
 */
public interface TransitionListener {

    /**
     * 监听LayoutTransition当前对应的transitionType类型动画开始
     * @param transition LayoutTransition对象实例
     * @param container LayoutTransition绑定的容器-container
     * @param view 当前在做动画的View对象
     * @param transitionType LayoutTransition类型,取值有:APPEARING、DISAPPEARING、
     *                       CHANGE_APPEARING、CHANGE_DISAPPEARING、CHANGING
     */
    public void startTransition(LayoutTransition transition, ViewGroup container,
                                View view, int transitionType);

    /**
     * 监听LayoutTransition当前对应的transitionType类型动画结束
     * @param transition LayoutTransition对象实例
     * @param container LayoutTransition绑定的容器-container
     * @param view 当前在做动画的View对象
     * @param transitionType LayoutTransition类型,取值有:APPEARING、DISAPPEARING、
     *                       CHANGE_APPEARING、CHANGE_DISAPPEARING、CHANGING
     */
    public void endTransition(LayoutTransition transition, ViewGroup container,
                              View view, int transitionType);
}

注释比较清晰,就不过多说明,我们如果想在某种transitionType类型动画开或者结束时设置某些操作,便可实现该接口,测试效果也比较简单,这里就不举例了。ok~,关于布局动画就先了解这么多吧。

关联文章:

 
标签: 安卓开发
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 安卓中通知功能的具体实现
    安卓中通知功能的具体实现
    通知[Notification]是Android中比较有特色的功能,当某个应用程序希望给用户发出一些提示信息,而该应用程序又不在前台运行时,就可以借助通知实现。使用通知的步骤1、需要一个NotificationManager来获得NotificationManager manager = (NotificationManager
    02-05 安卓开发
  • Android view系统分析-setContentView
    Android view系统分析-setContentView
    第一天上班,列了一下今年要学习的东西。主要就是深入学习Android相关的系统源代码,夯实基础。对于学习Android系统源代码,也没什么大概,就从我们平常使用最基础的东西学起,也就是从view这个切入点开始学习Android的源码,在没分析源码之前,我们有的时候
    02-05 安卓开发
  • 如何进行网络视频截图/获取视频的缩略图
    如何进行网络视频截图/获取视频的缩略图
    小编导读:获取视频的缩略图,截图正在播放的视频某一帧,是在音视频开发中,常遇到的问题。本文是主要用于点播中截图视频,同时还可以获取点播视频的缩略图进行显示,留下一个问题,如下图所示, 如果要获取直播中节目视频缩略图,该怎么做呢?(ps:直播是直
  • Android NDK 层发起 HTTP 请求的问题及解决
    Android NDK 层发起 HTTP 请求的问题及解决
    前言新的一年,大家新年快乐~~鸡年大吉!本次给大家带来何老师的最新文章~虽然何老师还在过节,但依然放心不下广大开发者,在此佳节还未结束之际,给大家带来最新的技术分享~ 事件的起因不说了,总之是需要实现一个 NDK 层的网络请求。为了多端适用,还是选择
  • Android插件化(六): OpenAtlasの改写aapt以防止资源ID冲突
    Android插件化(六): OpenAtlasの改写aapt以防
    引言Android应用程序的编译中,负责资源打包的是aapt,如果不对打包后的资源ID进行控制,就会导致插件中的资源ID冲突。所以,我们需要改写aapt的源码,以达到通过某种方式传递资源ID的Package ID,通过aapt打包时获取到这个Package ID并且应用才插件资源的命名
    02-05 安卓开发
  • Android架构(一)MVP架构在Android中的实践
    Android架构(一)MVP架构在Android中的实践
    为什么要重视程序的架构设计 对程序进行架构设计的原因,归根结底是为了 提高生产力 。通过设计是程序模块化,做到模块内部的 高聚合 和模块之间的 低耦合 (如依赖注入就是低耦合的集中体现)。 这样做的好处是使得程序开发过程中,开发人员主需要专注于一点,
    02-05 安卓开发
  • 安卓逆向系列教程 4.2 分析锁机软件
    安卓逆向系列教程 4.2 分析锁机软件
    安卓逆向系列教程 4.2 分析锁机软件 作者: 飞龙 这个教程中我们要分析一个锁机软件。像这种软件都比较简单,完全可以顺着入口看下去,但我这里还是用关键点来定位。首先这个软件的截图是这样,进入这个界面之后,除非退出模拟器,否则没办法回到桌面。上面那
    02-05 安卓开发
  • Android插件化(二):OpenAtlas插件安装过程分析
    Android插件化(二):OpenAtlas插件安装过程分析
    在前一篇博客 Android插件化(一):OpenAtlas架构以及实现原理概要 中,我们对应Android插件化存在的问题,实现原理,以及目前的实现方案进行了简单的叙述。从这篇开始,我们要深入到OpenAtlas的源码中进行插件安装过程的分析。 插件的安装分为3种:宿主启动时立
    02-05 安卓开发
  • [译] Android API 指南
    [译] Android API 指南
    众所周知,Android开发者有中文网站了,API 指南一眼看去最左侧的菜单都是中文,然而点进去内容还是很多是英文,并没有全部翻译,我这里整理了API 指南的目录,便于查看,如果之前还没有通读,现在可以好好看一遍。注意,如果标题带有英文,说明官方还没有翻
  • 使用FileProvider解决file:// URI引起的FileUriExposedException
    使用FileProvider解决file:// URI引起的FileUri
    问题以下是一段简单的代码,它调用系统的相机app来拍摄照片:void takePhoto(String cameraPhotoPath) {File cameraPhoto = new File(cameraPhotoPath);Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);takePhotoIntent.putExtra(Medi
    02-05 安卓开发
点击排行